Mittwoch, 7. Juli 2010

Analoge Uhr selbst gebaut / Self made analog clock

Nachdem ich im letzten Monat einen Eintrag bzgl. einer digitalen Anzeige gepostet habe fiel mir jetzt wieder ein altes Stück Code in die Finger, bei dem es sich um eine analoge Uhrzeitanzeige dreht. Nachdem ich den Staub entfernt und den Code ein wenig optimiert habe steht einem neuen Blogeintrag nichts mehr im Wege.

Damit das Codemuster funktioniert (und natürlich, damit die Analoguhr dem eigenen Geschmack angepaßt werden kann), sollten die u.a. Grafiken in einen Unterordner namens _bitmaps kopiert werden, der sinnvollerweise im VFP-Suchpfad liegt. Ist dies nicht so ohne weiteres möglich, dann muss halt ein wenig am Code rumgeschraubt werden ;-)







(Die beiden Pfeile sind für die Imageobjekte zum Wechsel des Hintergrundbilds gedacht.)

Das aus meiner Sicht interessante an diesem Codemuster dürfte, neben dem Algorithmus zum Positionieren der drei Line-Objekte, das minimalistische Dateihandling der Hintergrundbilder sein.

Diese werden im INIT in eine Array-Property (.PictureArray) eingelesen und über eine zweite Property (.CurrentImage) verwaltet. CurrentImage verfügt über eine _Assign-Methode, in welcher das jeweils nächste oder vorherige Bild zugewiesen wird.

Diese Vorgehensweise ermöglicht es uns, jederzeit neue Hintergrundbilder bereitzustellen. Sie müssen nur mit 'Clock' beginnen, vom Typ BMP sein und 100 * 100 Pixel messen.

Im u.a. Funktionstest ist die Entfernung des Objekts auskommentiert. Die Zeile kann jedoch problemlos über die Zwischenablage ins Befehlsfenster kopiert werden.

* // Funktionstest START    

_screen.AddObject([oClock],[cClock])
_screen.oClock.Visible = .T.
*_screen.removeobject([oClock])

* // Funktionstest ENDE        



DEFINE CLASS cClock AS container

    Width = 100
    Height = 100
    BackStyle = 0
    BorderWidth = 0
    currentimage = 0
    Name = "cClock"
    twopi = .F.
    DIMENSION picturearray[1,5]

    ADD OBJECT imgclock AS image WITH ;
        Stretch = 1, ;
        Height = 100, ;
        Left = 0, ;
        Top = 0, ;
        Width = 100, ;
        Name = "imgClock"

    ADD OBJECT timer1 AS timer WITH ;
        Top = 0, ;
        Left = 77, ;
        Height = 23, ;
        Width = 23, ;
        Interval = 1000, ;
        Name = "Timer1"

    ADD OBJECT lineh AS line WITH ;
        BorderWidth = 4, ;
        Height = 50, ;
        Left = 50, ;
        Top = 24, ;
        Width = 0, ;
        Name = "LineH"

    ADD OBJECT linem AS line WITH ;
        BorderWidth = 2, ;
        Height = 50, ;
        Left = 50, ;
        Top = 24, ;
        Width = 0, ;
        Name = "LineM"

    ADD OBJECT lines AS line WITH ;
        BorderWidth = 1, ;
        Height = 50, ;
        Left = 50, ;
        Top = 24, ;
        Width = 0, ;
        BorderColor = RGB(128,0,0), ;
        Name = "LineS"

    ADD OBJECT imgnext AS image WITH ;
        Picture = "_bitmaps\next.bmp", ;
        Height = 5, ;
        Left = 90, ;
        MousePointer = 15, ;
        Top = 90, ;
        Width = 6, ;
        Name = "imgNext"

    ADD OBJECT imgprev AS image WITH ;
        Picture = "_bitmaps\prev.bmp", ;
        Height = 5, ;
        Left = 5, ;
        MousePointer = 15, ;
        Top = 90, ;
        Width = 6, ;
        Name = "imgPrev"

    PROCEDURE calcanddraw
        LPARAMETERS nPartOf as Integer , nLineLen as Integer , oLine as Object
        LOCAL    liX as Integer , liY as Integer 

        * // Berechnung der x- und y- Koordinaten
        WITH This

            liX = 50 + COS( .TwoPi * ( -.25 + nPartOf ) ) * nLineLen
            liY = 50 + SIN( .TwoPi * ( -.25 + nPartOf ) ) * nLineLen

        ENDWITH 

        * // Berechnete Daten zuweisen
        WITH oLine

            .Top        = MIN( liY , 50 )
            .Left       = MIN( liX , 50 )
            .Height     = ABS( liY - 50 )
            .Width      = ABS( liX - 50 )
            .LineSlant  = IIF( ( liY > 50 ) # ( liX > 50 ) , [/] , [\] )

        ENDWITH 
    ENDPROC

    PROCEDURE drawtime
        LPARAMETERS lFromInit as Boolean
        LOCAL lcTime as String, liHour as Integer, liMinute as Integer, liSecond as Integer

        * // Uhrzeit zerlegen. Um sicherzustellen, dass mit 
        * // einem einheitlichen Wert gearbeitet wird er-
        * // folgt dies mit    einer Stringvariablen
        lcTime      = TIME()
        liHour      = VAL( GETWORDNUM( lcTime , 1 , [:] ) ) % 12
        liMinute    = VAL( GETWORDNUM( lcTime , 2 , [:] ) )
        liSecond    = VAL( GETWORDNUM( lcTime , 3 , [:] ) )

        WITH This

            * // Sekundenzeiger Position berechnen
            .CalcAndDraw( liSecond / 60 , 45 , .LineS )

            IF liSecond = 0 OR lFromInit

                * // Minutenzeiger Position berechnen
                .CalcAndDraw( liMinute / 60 , 40 , .LineM )
                * // Stundenzeiger Position berechnen
                .CalcAndDraw( ( liHour + liMinute / 60 ) / 12 , 30 , .LineH )

            ENDIF 

        ENDWITH 

        RELEASE lcTime , liHour , liMinute, liSecond
    ENDPROC

    PROCEDURE currentimage_assign
        LPARAMETERS vNewVal
        LOCAL lcPic as String

        WITH This

            .CurrentImage        = ICASE( ;
                                        vNewVal < 1 , ALEN( .PictureArray , 1 ) , ;
                                        vNewVal > ALEN( .PictureArray , 1 ) , 1 , ;
                                        vNewVal ;
                                       )
            .imgClock.Picture    = [_bitmaps\] + .PictureArray( .CurrentImage , 1 )
            .Refresh

        ENDWITH 
    ENDPROC

    PROCEDURE Init
        WITH This

            * // Alle Objekte einblenden
            .SetAll( [visible] , .T. , [line] )

            * // Arbeitsvariable füllen
            .TwoPi = 2 * PI()

            * // Uhrzeit initialisieren
            .DrawTime( .T. )

            * // Vorhandene Hintergrundbilder einlesen
            ADIR(.PictureArray,[_bitmaps\clock*.bmp],[],1)

            * // auf 1. Bild im Vektor positionieren
            .CurrentImage = 1

        ENDWITH 
    ENDPROC

    PROCEDURE timer1.Timer
        This.Parent.DrawTime
    ENDPROC

    PROCEDURE imgnext.Click
        WITH This.Parent

            .CurrentImage = .CurrentImage - 1

        ENDWITH 
    ENDPROC

    PROCEDURE imgprev.Click
        WITH This.Parent

            .CurrentImage = .CurrentImage + 1

        ENDWITH 
    ENDPROC

ENDDEFINE

1 Kommentar: