Freitag, 4. Juni 2010

Digitale Anzeige selbst gebaut / Self made digital display

Vor einiger Zeit hatte ich an dieser Stelle über mein Problem mit dem richtigen Timing bei meinem Tee geschrieben. Thema war damals das Abspielen von WAV-Dateien in VFP.

Was mich ursprünglich dazu veranlasst hatte, mir einen Teatimer zu programmieren war, dass ich einfach mal ausprobieren wollte, wie aufwändig die Erstellung einer digitalen Zahlenanzeige ist, OHNE einen ensprechenden Font einzusetzen. Mit anderen Worten: Welche Grafiken benötige ich und wie blende ich wann die richtigen image-Objekte ein, damit auch alles nach einer altmodischen LED-Anzeige aussieht.

Als erstes legte ich mich auf eine Zahlendarstellung mit Hilfe von 7 Elementen fest, schliesslich ging es nicht um Schönheit sondern um einen grundsätzlichen Funktionstest.

1    -
2u3 | |
4    -
5u6 | |
7    -

Als Grafiken benötigte ich somit 2 Basiselemente ( - und | ), einen Doppelpunkt als Trenner für Minuten und Sekunden sowie eine Hintergrundgrafik, welche in dunkelgrau die ausgeblendeten Elemente visualisieren sollte.




Nachdem die vier Grafiken verfügbar waren musste ich diese nur noch mit Hilfe von Image-Objekten in einen Container verfrachten und sauber positionieren. Der Container bekam den Namen 'cntDigit' und enthielt anschliessend sieben image-Objekte. Der Doppelpunkt und die Hintergrundgrafik kommen in meinem Code erst in einem Hauptcontainer zum Zuge, in dem mehrere 'cntDigit' Container nebeneinander positioniert werden und erkennbar als Stunde : Minute dargestellt werden sollen. Es spricht jedoch nichts dagegen, die 8er-Template bereits im Basiscontainer einzufügen. Der verwendete Code läßt dies ohne Änderung zu.


Optisch war nun alles in Butter. Nun kam die Ausprogrammierung der Klasse 'cntDigit' an die Reihe.

Zunächst war die Image-Klasse an der Reihe. Hier musste zwar kein Code hinterlegt werden, aber sowohl die waagerechten als auch die senkrechten Balken benötigten Eigenschaften, mit deren Hilfe eine Sichtbarkeit in Abhängigkeit von der anzuzeigenden Zahl möglich war. Hierfür erstellte ich 10 individuell zu setzende Eigenschaften die je nach Image-Position gefüllt werden.

Wie die 10 Eigenschaften vom Typ Boolean (-> _0, _1, _2, _3, ..., _9) zu füllen sind liegt letztlich an der Position des jeweiligen Image-Objektes. Wird das Objekt zur Darstellung der anzuzeigenden Zahl benötigt, erhält die Eigenschaft ein .T. andernfalls ein .F. (-> Default). Vorteil diese Methodik ist, dass eine Erweiterung auf eine komplexere Darstellung bzw. Erweiterung auf Buchstaben problemlos umzusetzen ist.

Um eine wertbezogene Anzeige zu generieren erhielt cntDigit zunächst einmal die Eigenschaft '_DisplayDigit' inkl. einer dazugehörigen Assign-Methode '_DisplayDigit_assign'. Zusätzlich kam noch die Methode 'initdigit' dazu, um den Container  'NICHTS' anzeigen zu lassen (Diese Methode wird im Teatimer immer nach dem Ablauf des Timers aufgerufen).

Innerhalb von '_DisplayDigit_assign' wird eine FOR..EACH Schleife durchlaufen, in der mit Hilfe von PEMSTATUS() überprüft wird, ob die zusammengesetzte Eigenschaft im Zielobjekt vorhanden ist. Anschliessend wird deren Wert einfach der Visible-Eigenschaft des Imageobjektes zugewiesen. Voilà, fertig war die digitale Zahlenanzeige. Da kommt einem doch sofort der Werbespruch eines ehemaligen Tennisprofis in den Sinn: Das ging ja einfach!!  ;-)

Hier nun das Codesegment von cntDigit:

* // Funktionstest    -START-    
WITH _screen

    .AddObject ( [oShape] , [Shape] )
    .oShape.Width = 48
    .oShape.Height = 82
    .oShape.BackColor = RGB( 0 , 0 , 0 )
    .oShape.Visible = .T.
    .AddObject ( [oTemplate], [imgTemplate] )
    .oTemplate.Top = 5
    .oTemplate.Left = 5
    .oTemplate.Visible = .T.
    .AddObject ( [oDigit] , [cntDigit] )

ENDWITH 

WITH _screen.oDigit
    
    .Top            = 5
    .Left            = 5
    .Visible        = .T.
    ._DisplayDigit    = [1]
    WAIT WINDOW [Taste für 2]
    ._DisplayDigit    = [2]
    WAIT WINDOW [Taste für 3]
    ._DisplayDigit    = [3]
    WAIT WINDOW [Taste für 4]
    ._DisplayDigit    = [4]
    WAIT WINDOW [Taste für 5]
    ._DisplayDigit    = [5]
    WAIT WINDOW [Taste für 6]
    ._DisplayDigit    = [6]
    WAIT WINDOW [Taste für 7]
    ._DisplayDigit    = [7]
    WAIT WINDOW [Taste für 8]
    ._DisplayDigit    = [8]
    WAIT WINDOW [Taste für 9]
    ._DisplayDigit    = [9]
    WAIT WINDOW [Taste für 0]
    ._DisplayDigit    = [0]
    WAIT WINDOW [Schliessen]

ENDWITH 

WITH _screen

    .RemoveObject( [oDigit] )
    .RemoveObject( [oTemplate] )
    .RemoveObject( [oShape] )

ENDWITH 
* // Funktionstest    -ENDE-    

DEFINE CLASS cntdigit AS container

    Width = 38
    Height = 71
    BackStyle = 0
    BorderWidth = 0
    _displaydigit = ""
    Name = "cntdigit"

    ADD OBJECT imgom AS imgdigithorizontal WITH ;
        Left = 5, ;
        Top = 0, ;
        Visible = .F., ;
        _0 = .T., ;
        _1 = .F., ;
        _2 = .T., ;
        _3 = .T., ;
        _4 = .F., ;
        _5 = .T., ;
        _6 = .T., ;
        _7 = .T., ;
        _8 = .T., ;
        _9 = .T.
        
    ADD OBJECT imgum AS imgdigithorizontal WITH ;
        Left = 5, ;
        Top = 62, ;
        Visible = .F., ;
        _0 = .T., ;
        _1 = .F., ;
        _2 = .T., ;
        _3 = .T., ;
        _4 = .F., ;
        _5 = .T., ;
        _6 = .T., ;
        _7 = .F., ;
        _8 = .T., ;
        _9 = .T.

    ADD OBJECT imgmm AS imgdigithorizontal WITH ;
        Left = 5, ;
        Top = 31, ;
        Visible = .F., ;
        _0 = .F., ;
        _1 = .F., ;
        _2 = .T., ;
        _3 = .T., ;
        _4 = .T., ;
        _5 = .T., ;
        _6 = .T., ;
        _7 = .F., ;
        _8 = .T., ;
        _9 = .T.

    ADD OBJECT imgol AS imgdigitvertical WITH ;
        Left = 0, ;
        Top = 6, ;
        Visible = .F., ;
        _0 = .T., ;
        _1 = .F., ;
        _2 = .F., ;
        _3 = .F., ;
        _4 = .T., ;
        _5 = .T., ;
        _6 = .T., ;
        _7 = .F., ;
        _8 = .T., ;
        _9 = .T.

    ADD OBJECT imgur AS imgdigitvertical WITH ;
        Left = 29, ;
        Top = 37, ;
        Visible = .F., ;
        _0 = .T., ;
        _1 = .T., ;
        _2 = .F., ;
        _3 = .T., ;
        _4 = .T., ;
        _5 = .T., ;
        _6 = .T., ;
        _7 = .T., ;
        _8 = .T., ;
        _9 = .T.

    ADD OBJECT imgul AS imgdigitvertical WITH ;
        Left = 0, ;
        Top = 37, ;
        Visible = .F., ;
        _0 = .T., ;
        _1 = .F., ;
        _2 = .T., ;
        _3 = .F., ;
        _4 = .F., ;
        _5 = .F., ;
        _6 = .T., ;
        _7 = .F., ;
        _8 = .T., ;
        _9 = .F.

    ADD OBJECT imgor AS imgdigitvertical WITH ;
        Left = 29, ;
        Top = 6, ;
        Visible = .F., ;
        _0 = .T., ;
        _1 = .T., ;
        _2 = .T., ;
        _3 = .T., ;
        _4 = .T., ;
        _5 = .F., ;
        _6 = .F., ;
        _7 = .T., ;
        _8 = .T., ;
        _9 = .T.

    PROCEDURE _displaydigit_assign
        LPARAMETERS vNewVal

        * // Einblenden der für die darzustellende Zahl
        * // benötigten Bits. Gesteuert wird dies über
        * // die Properties _0 - _9 die über die 
        * // FOR...EACH Schleife direkt ausgewertet werden.

        IF This._DisplayDigit <> m.vNewVal

            LOCAL lcProperty as String
            This._DisplayDigit = m.vNewVal

            FOR EACH oDigit IN This.Controls
                lcProperty = [_] + This._DisplayDigit
                IF PEMSTATUS(oDigit,lcProperty,5)
                    oDigit.Visible = oDigit.&lcProperty
                ENDIF 
            ENDFOR 

        ENDIF 
    ENDPROC

    PROCEDURE initdigit
        * // Ausblenden sämtlicher Bits
        FOR EACH oDigit IN This.Controls
            oDigit.Visible = .F.
        ENDFOR 
    ENDPROC

ENDDEFINE

DEFINE CLASS imgdigithorizontal AS image

    Picture = "..\_bitmaps\inf_digit_horizontal.bmp"
    BackStyle = 0
    Height = 9
    Width = 28
    _1 = .F.
    _2 = .F.
    _3 = .F.
    _4 = .F.
    _5 = .F.
    _6 = .F.
    _7 = .F.
    _8 = .F.
    _9 = .F.
    _0 = .F.

ENDDEFINE

DEFINE CLASS imgdigitvertical AS image

    Picture = "..\_bitmaps\inf_digit_vertical.bmp"
    Height = 28
    Width = 9
    _1 = .F.
    _2 = .F.
    _3 = .F.
    _4 = .F.
    _5 = .F.
    _6 = .F.
    _7 = .F.
    _8 = .F.
    _9 = .F.
    _0 = .F.

ENDDEFINE

DEFINE CLASS imgTemplate AS image

    Picture = "..\_bitmaps\inf_digit_template.bmp"
    Height = 71
    Width = 38

ENDDEFINE

4 Kommentare:

  1. This is very very cool !
    Thanks for sharing
    Regards
    Cesar

    AntwortenLöschen
  2. Hi Cesar,

    I'm glad you like it :-)

    -Tom

    AntwortenLöschen
  3. Hi Thomas,

    hmm, da haste wohl das Rad nochmal neu erfunden ;) Guggst du hier:
    http://code.msdn.microsoft.com/FoxPro/Release/ProjectReleases.aspx?ReleaseId=131
    Datt Dingens hatte ich mal anno 2004 "erfunden" für ein Kassensystem.

    AntwortenLöschen
  4. Hi wOOdy,

    Deine Variante ist ein interessanter Ansatz. Auf den Einsatz von Shapes hatte ich gezielt verzichtet, weil ich bei einer Erhöhung der LED-Objekte zu viele Überlappungen hätte. Aber für mich war es halt einfach nur ein wenig Rumspielen mit der Aufgabenstellung. An einen Echteinsatz wie bei Kassensystemen hatte ich überhaupt nicht gedacht. Wenn es um Resizing geht bist Du mit den Shapes sicherlich flexibler!

    Auf jeden Fall haben wir mal wieder ein Beispiel dafür, dass viele Wege nach Rom führen :-)))

    AntwortenLöschen