Freitag, 25. Juni 2010

Erzeugen von UNC Pfadnamen / Creating UNC Pathnames (Revisited)

Nachdem ich heute zufälligerweise in eine alte Funktion von mir reingeschaut habe (Erzeugen von UNC-Pfadnamen), gab es auch gleich Verbesserungsbedarf. Im Blogeintrag vom September 2008 konnte nur ein Laufwerksbuchstabe (bspw. H:) übergeben werden. Die neue Funktion habe ich nun dahingehend erweitert, dass es jetzt sowohl reine Laufwerksbuchstaben, als auch komplette Verzeichnis- und/oder Dateinamen sein dürfen. Die verschiedenen Möglichkeiten sind im vorgelagerten Funktionstest zu ersehen.

* // Funktionstest Start    
CLEAR 
?GetFullUNCPath( [H:] )
?GetFullUNCPath( [H:\] )
?GetFullUNCPath( [H:\Foxprogs] )
?GetFullUNCPath( [H:\Foxprogs\] )
?GetFullUNCPath( [H:\Foxprogs\mware71] )
?GetFullUNCPath( [H:\Foxprogs\mware71\] )
?GetFullUNCPath( [H:\Foxprogs\mware71\konf.exe] )
* // Funktionstest Ende        

FUNCTION GetFullUNCPath as String
LPARAMETERS vMappedName as String
    * // Datendeklaration und Initialisierung            
    LOCAL    lcUNCBuffer as String, liLength as Integer, ;
            lcUNCName as String, llContinue as Boolean, ;
            lcMessage as String, lcPath as String
    lcUNCBuffer    = []
    liLength    = 0
    lcUNCName    = []
    llContinue    = .T.
    lcMessage    = []
    vMappedName    = IIF(DIRECTORY( vMappedName ) , ADDBS( vMappedName ) , vMappedName )
    lcPath        = IIF( LEN( vMappedName ) > 2 , SUBSTR( vMappedName , 3 ) , [] )
    vMappedName    = JUSTDRIVE( vMappedName )
    * // Deklaration der API-Funktion                    
    TRY
        DECLARE INTEGER WNetGetConnection IN WIN32API ;
            STRING @ lpLocalName, ;
            STRING @ lpRemoteName, ;
            INTEGER @ lpliLength
    CATCH
        TEXT TO lcMessage NOSHOW TEXTMERGE PRETEXT 2
            Deklaration von WNetGetConnection in WIN32API
            ist fehlgeschlagen. Funktion wird vorzeitig beendet.
        ENDTEXT
        MESSAGEBOX(lcMessage,0+16+0,[Information])
        llContinue = .F.
    ENDTRY
    * // Umsetzung des lokalen Pfades in einen UNC Pfad    
    IF llContinue
        IF !EMPTY( vMappedName ) AND VARTYPE( [vMappedName] ) = [C]
            lcUNCBuffer    = REPL( CHR( 0 ) , 261 )
            liLength    = LEN( lcUNCBuffer )
            vMappedName    = ALLTRIM( vMappedName )
            IF LEN( vMappedName ) = 1
                vMappedName = vMappedName + [:]
            ENDIF
            TRY
                IF WNetGetConnection( vMappedName , @lcUNCBuffer , @liLength ) = 0
                    lcUNCName = LEFT( lcUNCBuffer , AT( CHR( 0 ) , lcUNCBuffer ) - 1 )
                ENDIF
            CATCH
                TEXT TO lcMessage NOSHOW TEXTMERGE PRETEXT 2
                    Aufruf von WNetGetConnection in WIN32API
                    ist fehlgeschlagen. UNC-Pfad konnte nicht
                    generiert werden.
                ENDTEXT
                MESSAGEBOX( lcMessage , 0+16+0 , [Information] )
            ENDTRY
        ENDIF
    ENDIF
    RETURN lcUNCName + lcPath
ENDFUNC

Dienstag, 15. Juni 2010

Marquee Texte schnell und einfach erzeugen / Creating marquee texts quick and easy

Wenn wir mit einfachen Mitteln einen Lauftext (Marquee) erzeugen bzw. darstellen wollen, dann ist alles, was wir benötigen eine Containerklasse mitsamt Label- und Timerobjekt. Dem Container verpassen wir noch einen Eigenschaft, mit welcher die Laufrichtung bzw. das Verhalten beim Verlassen des sichtbaren Bereiches gesteuert wird und fertig ist die Laube.

Der folgende Mustercode kann, wenn als PRG in Foxpro gestartet, über das Befehlsfenster direkt beeinflußt werden. Ausschlaggebend hierfür ist die Eigenschaft _screen.oMover._Mode. Sie verarbeitet die Werte 1 - 4 (Siehe Kommentare im Block Funktionstest des Codebeispiels). Defaultwert ist die 2 (Von rechts nach links bewegen).

* // Funktionstest -START-

_screen.AddObject([oMover],[cntMover])
_screen.oMover.Visible = .T.
* // kontinuierlich nach rechts scrollen        
* _screen.oMover._Mode = 1
* // kontinuierlich nach links scrollen    
* _screen.oMover._Mode = 2
* // JoJo-Effekt nach links initiieren        
* _screen.oMover._Mode = 3
* // JoJo-Effekt nach rechts initiieren        
* _screen.oMover._Mode = 4
* // Mover-Objekt entsorgen...                
*_screen.RemoveObject([oMover])



* // Funktionstest -ENDE-


DEFINE CLASS cntmover AS container

    Anchor = 14
    Width = 570
    Height = 20
    BackColor = RGB(128,128,128)
    Name = [cntmover]
    _Mode = 2

    ADD OBJECT lblmove AS label WITH ;
        AutoSize = .T., ;
        BackStyle = 0, ;
        Caption = [Timer basierender Marquee Text], ;
        Height = 17, ;
        Left = 1, ;
        Top = 3, ;
        Width = 280, ;
        ForeColor = RGB(255,255,255), ;
        Name = [lblMove]

    ADD OBJECT tmrmove AS timer WITH ;
        Top = 1, ;
        Left = 1, ;
        Height = 23, ;
        Width = 23, ;
        Interval = 20, ;
        Name = [tmrMove]

    PROCEDURE tmrmove.Timer
    
        WITH This.Parent

            DO CASE 
            CASE ._Mode = 1
            
                .lblMove.Left = .lblMove.Left - 1
                IF .lblMove.Left < .lblMove.Width * (-1)
                    .lblMove.Left = .Width
                ENDIF
                
            CASE ._Mode = 2
            
                .lblMove.Left = .lblMove.Left + 1
                IF .lblMove.Left > .Width
                    .lblMove.Left = .lblMove.Width * (-1)
                ENDIF
                
            CASE ._Mode = 3
            
                .lblMove.Left = .lblMove.Left - 1
                IF .lblMove.Left + .lblMove.Width < 1
                    ._Mode = 4
                ENDIF 
                
            CASE ._Mode = 4
            
                .lblMove.Left = .lblMove.Left + 1
                IF .lblMove.Left > .Width
                    ._Mode = 3
                ENDIF 
                
            ENDCASE 

        ENDWITH 
        
    ENDPROC

ENDDEFINE

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