Rubrik: Forms/Controls | VB-Versionen: VB6 | 01.10.08 |
![]() Mit diesem Workshop wird eine Möglichkeit aufgezeigt, InfoBoxen bzw. Informationen außerhalb der eigenen Anwendung darzustellen, und zwar so, dass nur der reine Text bzw. die Controls sichtbar sind, d.h. die Form selbst wird transparent dargestellt. | ||
Autor: Robert | Bewertung: ![]() ![]() ![]() ![]() ![]() | Views: 13.353 |
Denjenigen, die schon einmal vergeblich versucht haben, Informationen außerhalb der eigenen Form so darzustellen, dass man wirklich nur die Zeichen selbst und kein Formular etc. sieht, sei hier und heute geholfen.
Das Problem:
Man möchte zum Beispiel über der Oberfläche eines Fremdprogramms eine Information wie etwa die aktuelle Systemzeit darstellen, weiß aber nicht wie, denn auf die Programmoberfläche des
Fremdprogramms kann - wenn überhaupt - nur schwer zugegriffen werden und passende API-Funktionen sind mir auch nicht bekannt.
Die Lösung:
Es ist eigentlich recht simpel. Man nimmt sich ein kleines Formular, setzt ein Label drauf und stellt es transparent über dem Fremdprogramm dar. Um das aber universeller zu gestalten, werden
wir diese Funktion heute in einem Modul verankern.
Soweit das Grobe, jetzt noch einmal langsam ;)
Starten Sie ein neues Projekt und fügen Sie noch eine Form hinzu. Nennen wir sie „frmBase". Platzieren Sie weiterhin ein Label auf dieser Form. Um den bestmöglichen Transparenzeffekt zu erzielen, sollte man noch folgende Einstellungen vornehmen:
frmBase.BorderStyle = 0 Label1.BackStyle = 1
Durch die erste Zeile nehmen wir dem Formular seine Titelleiste weg (und somit uns die Möglichkeit, es wie gewohnt zu verschieben - das muss aus unserer Hauptform heraus geschehen). Die zweite Zeile dient lediglich dem Effekt der Transparenz.
Nun machen wir uns an das Modul. Fügen Sie eins Ihrem Projekt hinzu und nennen Sie es „modInfoBox".
Im Deklarationsteil brauchen wir folgenden Code:
Option Explicit Dim frm2() As Form Private Counter As Integer Dim i As Integer Private Declare Function SetWindowPos Lib "user32" ( _ ByVal hwnd As Long, _ ByVal hWndInsertAfter As Long, _ ByVal x As Long, _ ByVal y As Long, _ ByVal cx As Long, _ ByVal cy As Long, _ ByVal wFlags As Long) As Long Private Const HWND_TOPMOST = -1 Private Const HWND_NOTOPMOST = -2 Private Const SWP_NOMOVE = &H2 Private Const SWP_NOSIZE = &H1
Erläuterung: frm2() ist ein Array, das Formen beinhaltet. Hier werden wir nachher dynamisch unsere InfoBoxen hineinladen. Die Variable Counter wird die Anzahl unserer InfoBoxen zählen und die Variable i ist die Zählvariable einer For-Schleife. Die API-Funktion SetWindowPos und die 4 dazugehörigen Konstanten brauchen wir erst später, nämlich um unsere InfoBoxen, wenn wir das wollen, permanent in den Vordergrund zu setzen.
Bevor wir jetzt mit modInfoBox fortfahren können, brauchen wir ein weiteres Modul namens modTransparentForm mit folgendem Code:
Option Explicit Private Declare Function GetWindowLong Lib "user32" _ Alias "GetWindowLongA" ( _ ByVal hwnd As Long, _ ByVal nIndex As Long) As Long Private Declare Function SetWindowLong Lib "user32" _ Alias "SetWindowLongA" ( _ ByVal hwnd As Long, _ ByVal nIndex As Long, _ ByVal dwNewLong As Long) As Long Private Declare Function SetLayeredWindowAttributes Lib "user32" ( _ ByVal hwnd As Long, _ ByVal crey As Long, _ ByVal bAlpha As Byte, _ ByVal dwFlags As Long) As Long Private Const gwl_ExStyle = (-20) Private Const ws_Ex_Layered = &H80000 Private Const LWA_ALPHA = &H2& Private Const lwa_ColorKey = 1
Public Sub setTransparencyFormOnly(Form As Form, _ ColorToFade As ColorConstants) Call SetWindowLong(Form.hwnd, gwl_ExStyle, _ GetWindowLong(Form.hwnd, gwl_ExStyle) Or ws_Ex_Layered) Call SetLayeredWindowAttributes(Form.hwnd, ColorToFade, 0, lwa_ColorKey) End Sub
Public Sub setTransparencyAlsoControls(Form As Form, _ TransparencyLevel As Byte) Call SetWindowLong(Form.hwnd, gwl_ExStyle, _ GetWindowLong(Form.hwnd, gwl_ExStyle) Or ws_Ex_Layered) Call SetLayeredWindowAttributes(Form.hwnd, 0, TransparencyLevel, LWA_ALPHA) End Sub
Public Sub setToNormal(Form As Form) Call SetWindowLong(Form.hwnd, gwl_ExStyle, _ GetWindowLong(Form.hwnd, gwl_ExStyle) And (Not ws_Ex_Layered)) Call SetLayeredWindowAttributes(Form.hwnd, 0, 255, LWA_ALPHA) End Sub
In diesem Modul erledigen wir alles, was mit Transparenz zu tun hat. Im Groben wird hier mit den drei API's die WindowLong-Eigenschaft verändert. Und zwar gibt es da verschiedene Möglichkeiten:
- setTransparencyFormOnly: Diese Funktion macht ein Formular transparent - aber nur das Formular, nicht die Steuerelemente, die es besitzt! Dies geschieht anhand einer vorher
festgelegten Farbe, die der Funktion via ColorToFade übergeben wird. Will ich also meine Form transparent haben, setze ich zuerst die BackColor z.B. auf vbRed und rufe dann die Funktion auf,
indem ich als ersten Parameter mein Formular und als zweiten einfach vbRed übergebe.
- setTransparencyAlsoControls: Hier werden auch die Controls transparent gemacht. Und zwar geschieht das nicht wie eben anhand einer Farbe, sondern es wird dem Formular als Ganzes
ein Alpha-Wert zugewiesen, der der Funktion über das Argument TransparencyLevel übergeben wird. Dabei bedeutet 0 völlige Transparenz und 255 die „normale" Transparenz, nämlich keine.
- setToNormal: Wie der Name schon sagt, wird die Transparenz eines Fensters hier wieder aufgehoben.
Damit ist unser Transparenz-Modul fertig. Es kann übrigens bei jedem VB-Projekt benutzt werden.
Kommen wir nun zurück zu unserem „Hauptmodul" modInfoBox.
Zuerst einige Hilfsfunktionen. Ich werde nun größtenteils auf die Erläuterungen verzichten, da der Code ausreichend kommentiert ist.
' Schließt eine einzelne InfoBox ' Param: Index = Indexnummer der jeweiligen InfoBox Public Sub TerminateInfoBox(index As Integer) Unload frm2(index) End Sub
' Schließt alle InfoBoxen ' Rückgabe: Anzahl der geschlossenen InfoBoxen Public Function TerminateAllInfoBoxes() As Long Dim tmpCount As Long Dim i As Long ' Unload für jedes Element im Array For i = 0 To UBound(frm2()) Unload frm2(i) tmpCount = tmpCount + 1 Next i ReDim Preserve frm2(0) Counter = 0 TerminateAllInfoBoxes = tmpCount End Function
' Macht alle InfoBoxen wieder undurchsichtig Public Sub setAllInfoBoxesIntransparent() Dim i As Long For i = 0 To UBound(frm2()) modTransparentForm.setToNormal frm2(i) Next i End Sub
' Macht alle InfoBoxen transparent Public Sub setAllInfoBoxesTransparent() Dim i As Long For i = 0 To UBound(frm2()) modTransparentForm.setTransparencyFormOnly frm2(i), frm2(i).BackColor Next i End Sub
' Bindet eine einzelne InfoBox an den Vordergrund ' Param: Index = Indexnummer der jeweiligen InfoBox Public Sub setSingleInfoBoxToTop(ByVal index As Long) setFormOnTop frm2(index).hwnd, True End Sub
' Bindet alle InfoBoxen an den Vordergrund Public Sub setAllInfoBoxesToTop() Dim i As Long For i = 0 To UBound(frm2()) setFormOnTop frm2(i).hwnd, True Next i End Sub
' Löst eine einzelne InfoBox vom Vordergrund, so dass wieder normal ' Param: Index = Indexnummer der jeweiligen InfoBox Public Sub releaseSingleInfoBoxFromTop(ByVal index As Long) setFormOnTop frm2(index).hwnd, False End Sub
' Löst alle InfoBoxen vom Vordergrund, so dass wieder normal Public Sub releaseAllInfoBoxesFromTop() Dim i As Long For i = 0 To UBound(frm2()) setFormOnTop frm2(i).hwnd, False Next i End Sub
' Greift auf eine InfoBox zu und verändert sie ' Param: Index = Indexnummer der jeweiligen InfoBox Public Sub EditInfoBox(ByVal index As Integer, ByVal Display1 As String) frm2(index).Label1.Caption = Display1 End Sub
' Greift auf alle InfoBoxen zu und verändert sie ' Param: Display1 = String, der dargestellt werden soll ' Rückgabe: Anzahl der veränderten InfoBoxen ' ' Anmerkung: Diese Funktion muss auf die individuelle InfoBox-Form ' zugeschnitten sein Public Function EditAllInfoBoxes(ByVal Display1 As String) As Long Dim i As Long EditAllInfoBoxes = 0 For i = 0 To UBound(frm2()) frm2(i).Label1.Caption = Display1 EditAllInfoBoxes = EditAllInfoBoxes + 1 Next i End Function
' Bindet ein Fenster an den Vordergrund ' Param: hwnd = Fensternummer des entspr. Fensters ' OnTop = Fenster immer im Vordergrund -> ja/nein Public Sub setFormOnTop(ByVal hwnd As Long, ByVal OnTop As Boolean) If OnTop Then ' immer im Vordergrund SetWindowPos hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE Else ' normal SetWindowPos hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE End If End Sub
Soweit die ganzen kleinen Nebenfunktionen. Jetzt schreiten wir voran zum Herz unseres Moduls, nämlich zu der Funktion, die die InfoBox erstellt:
' Erstellt eine transparente InfoBox auf Basis eines Formulars ' Param: FormSource = Modell der InfoBox ' ColorToFade (optional) = Farbe, die transparent gemacht werden ' soll. Wenn weggelassen, wird keine ' Transparenz gezeigt ' TwipsX = X-Position der InfoBox in Twips ' TwipsY = Y-Position der InfoBox in Twips ' FormOnTop = InfoBox immer im Vordergrund? ' ' Rückgabe: Index der gerade erzeugten InfoBox im Form-Array Public Function CreateNewInfoBox(FormSource As Form, _ ByVal TwipsX As Long, ByVal TwipsY As Long, _ Optional ByVal FormOnTop As Boolean = False, _ Optional ByVal ColorToFade As ColorConstants = -1) As Long ' dem Array, das die InfoBoxen beinhaltet, eine weitere InfoBox hinzufügen ReDim Preserve frm2(0 To Counter) Set frm2(Counter) = FormSource ' InfoBox bauen Load frm2(Counter) With frm2(Counter) .Label1.BackStyle = 0 ' wenn der optionale Parameter ColorToFade angegeben wurde: If ColorToFade <> -1 Then .BackColor = ColorToFade .BorderStyle = 0 .Left = TwipsX .Top = TwipsY .Show End With ' wenn gewünscht, InfoBox in den Vordergrund If FormOnTop = True Then setFormOnTop frm2(Counter).hwnd, True ' Transparenz setzen, wenn ColorToFade angegeben If ColorToFade <> -1 Then modTransparentForm.setTransparencyFormOnly frm2(Counter), ColorToFade End If ' aktuellen Index zurückgeben, damit die einzelnen InfoBoxen später ' besser angesprochen werden können CreateNewInfoBox = Counter Counter = Counter + 1 End Function
Ich bitte zu beachten, dass die Koordinatenangaben in Twips gemacht werden müssen! Wer die Angaben nur in Pixel hat, kann auf folgenden Tipp zurückgreifen:
Umrechnung Twips in Pixel und umgekehrt
Nun sind wir eigentlich fertig mit den Modulen. Jetzt kann getestet werden
Dazu nehmen wir uns wieder unser Startformular Form1, platzieren ein paar Buttons und probieren nach Herzenslust aus. Hier ein paar Beispiele für die Funktionsaufrufe:
' 3 InfoBoxen erstellen und gleich mit Text ausstatten Dim index As Long index = modInfoBox.CreateNewInfoBox(New frmStatus, 2000, 2000, True, vbGreen) modInfoBox.EditInfoBox index, "Index Nr. " & index index = modInfoBox.CreateNewInfoBox(New frmStatus, 3000, 3000, True, vbGreen) modInfoBox.EditInfoBox index, "Index Nr. " & index index = modInfoBox.CreateNewInfoBox(New frmStatus, 4000, 4000, True, vbGreen) modInfoBox.EditInfoBox index, "Index Nr. " & index MsgBox "Childs: " & index + 1
' Alle InfoBoxen transparent modInfoBox.setAllInfoBoxesTransparent
' Alle InfoBoxen wieder normal modInfoBox.setAllInfoBoxesIntransparent
' Alle InfoBoxen editieren ' Rückgabe ist die Anzahl der veränderten InfoBoxen MsgBox modInfoBox.EditAllInfoBoxes("Und sie dreht sich doch!")
' Alle InfoBoxen schließen ' Rückgabe ist die Anzahl der geschlossenen InfoBoxen MsgBox modInfoBox.TerminateAllInfoBoxes & " Fenster geschlossen"
' Alle InfoBoxen in den Vordergrund holen modInfoBox.setAllInfoBoxesToTop
' Alle InfoBoxen nicht mehr permanent an den Vordergrund bilden modInfoBox.releaseAllInfoBoxesFromTop
Das waren nur ein paar mögliche Aufrufe. Viele Funktionen, die sich auf alle geöffneten InfoBoxen beziehen, existieren auch noch als Variante, die sich auf nur eine InfoBox bezieht. Hierbei muss der Index der InfoBox bekannt sein, der bei der Create-Funktion zurückgegeben wird.
Ich hoffe ich habe meinen ersten Workshop relativ verständlich geschrieben und einigen, die das selbe Problem hatten wie ich, weiterhelfen können.
Viel Spaß damit