Buttons - freischwebend über dem Desktop... Ein interessanter Effekt ist das, nicht wahr?
Ganz einfach, werden Sie sagen, die Buttons werden mit der API-Funktion SetParent auf den Desktop verschoben. Und das Form, von dem die Buttons stammen, bleibt eben unsichtbar. Ja, so könnten wir das gemacht haben. Beispielsweise dürfte es dann jedoch nicht so einfach gewesen sein, die gezeigte Verschiebung aller Buttons auf einmal sauber hinzubekommen. Aber natürlich - wenn wir schon so scheinheilig fragen, dann steckt bestimmt etwas anderes dahinter...
Richtig - es handelt sich hier nämlich um ein transparentes Form. Das Beispiel zeigt, wie Sie etwa mit einem solchen transparenten Form raffinierte Intro-Forms für Ihre Anwendungen erstellen können - und vieles mehr. Ihrer Phantasie sind fast keine Grenzen gesteckt.
Wenn Sie nun vermuten, wir hätten mit den Fensterstilen hantiert, dem Form also nachträglich die Einstellung WS_EX_TRANSPARENT untergejubelt, dann täuschen Sie sich allerdings erneut. Wir haben mit dieser Möglichkeit experimentiert. Aber die Ergebnisse waren nicht so recht befriedigend. Vor allem dann nicht, wenn wir zur Laufzeit den Zustand zwischen transparent und nicht-transparent wechseln wollten. Immer gab es unerwünschte Effekte, die uns letztendlich diesen Ansatz als untauglich verwerfen ließen.
Nach ein paar weiteren Forschungen und Überlegungen stießen wir auf die relativ unbekannte Möglichkeit, dass man die Kontur eines Forms, also eines Windows-Fensters, über die Zuweisung einer neuen Fenster-Region nahezu beliebig manipulieren kann. Das ist zwar etwas aufwändiger, aber garantiert dafür den erhofften Effekt, nämlich ein Form bis auf die Flächen der darauf platzierten Steuerelemente unsichtbar, also transparent werden zu lassen.
Der Lösungsweg beruht auf der Definition und der Kombination von Regionen. Dabei kommen uns zwei Umstände entgegen. Zum einen sind Steuerelemente von Haus aus rechteckig. Und zum zweiten können wir über die Controls-Auflistung eines Forms alle darauf platzierten Steuerelemente ausfindig machen. Wir durchlaufen einfach die Auflistung in einer Schleife, ermitteln die Rechtecke der sichtbaren Steuerelemente und transformieren diese mittels der API-Funktion CreateRectRgn in Regionen. Dann kombinieren wir diese Regionen so, dass sie sich gegenseitig ausschließen (API-Funktion CombineRgn mit RGN_OR) und übertragen zum Schluss die Ergebnis-Region mit SetWindowRgn auf das Form.
So einfach dieses Verfahren auch klingt - es gibt ein par wenige Stolpersteine, die aus dem Weg zu räumen sind.
So dürfen wir die auf diese Weise erzeugte Region, bzw. deren Handle, erst löschen, wenn sie durch eine neue Definition einer Region ersetzt werden soll. Das wird erforderlich, wenn sich die Positionen oder Sichtbarkeiten von Steuerelementen ändern sollten, oder wenn wir die Transparenz des Forms im Ganzen zurücknehmen wollen.
In ersterem Fall erstellen wir einfach eine neue Region nach dem beschriebenen Verfahren und löschen das alte Region-Handle vor der Zuweisung des Neuen. Im zweiten Fall weisen wir über SetWindowRgn lediglich ein Null-Handle zu, nachdem wird das alte Handle gelöscht haben, und Windows restauriert automatisch wieder die unverfälschte, originale Region des Forms.
Einen weitaus dickerer Stolperstein legt uns Visual Basic mit den Steuerelementen in den Weg, die keine echten Windows-Steuerelemente sind und daher keine eigenen Fenster-Handles haben. Es wäre nämlich am einfachsten, die Rechtecke der Steuerelemente, und damit die zur Definition der Regionen benötigten absoluten Positionen in Bildschirmkoordinaten, über die API-Funktion GetWindowRect zu ermitteln. Doch da diese Funktion ja nur für Windows-Fenster gilt (und echte Windows-Steuerelemente sind Windows-Fenster), müssten wir entweder Steuerelemente wie Labels, Image-Controls usw. ignorieren (sie würden mit dem Form zusammen unsichtbar), oder einen anderen Weg finden.
Dieser andere Weg führt über die Ermittlung der relativen Positionen der Steuerelemente im Arbeitsbereich des Forms dem sogenannten Client-Rechteck (ClientRect). Die Positionsangaben von Steuerelementen beziehen sich ja nicht auf die Außenkontur eines Forms, sondern auf einen darin liegenden, um verschiedene Elemente wie Rahmen, Titelleiste und Menüs verkleinerten Bereich. Geben Sie einem Form einfach einmal eine andere Hintergrundfarbe, dann erkennen Sie diesen Bereich deutlich. Über die API-Funktion GetClientRect bekommen Sie sogar dessen exakte Größe - nur leider nicht seine exakte Position in absoluten Bildschirmkoordinaten. Sie könnten die Position des ClientRects zwar mit Hilfe der zu jedem Fenster ermittelbaren Daten zu Rahmen, Titelleiste usw. berechnen ( GetSystemMetrics). Jedoch spätestens ein vom Anwender sehr schmal gemachtes Form mit vielen Elementen in der Menüzeile lässt diese Berechnungen wegen des Umbruchs der Menüzeile wertlos werden. Sie können einfach nicht ermitteln, über wie viele Zeilen sich die Menüleiste aktuell erstreckt - wie hoch die Menüzeile also tatsächlich ist.
Für Abhilfe sorgt ein kleiner Trick. Was wir benötigen, wäre ein Steuerelement, das sich exakt in der linken oberen Ecke des ClientRects befindet. Wir wollen jedoch die Funktion des Ganzen nicht davon abhängig machen, dass extra ein ansonsten überflüssiges Steuerelement in dem Form platziert werden muss. Darum erschaffen wir dieses Dummy-Steuerelement nur vorübergehend und lassen es gerade so lange leben, bis wir seine Bildschirmposition ermittelt haben.
Aus Position und Größe des Forms und der anhand des Dummy-Steuerelements ermittelten Position des ClientRects und aus dessen Größe ermitteln wir die relativen Verschiebungen in X- und Y-Richtung der auf dem Form platzierten Steuerelemente gegenüber dem Rechteck des Forms. Dieses Verfahren ist sozusagen narrensicher - es funktioniert immer, egal, welchen Rahmenstil das Form hat, ob es ein Menü hat, oder welche Werte der Anwender auf seinem System für die Höhe der Titelleiste, die Rahmenstärke usw. eingestellt hat.
Einen Haken hat der Trick allerdings doch: Das dynamische Laden eines Steuerelements ist erst ab Visual Basic 6 möglich. Unter Visual Basic 5 müssten Sie sich darauf verlassen können, dass auf dem Form wenigstens ein echtes Windows-Steuerelement (ein Steuerelement mit der hWnd-Eigenschaft) vorhanden ist - mit dessen Hilfe können Sie dann den oben beschriebenen Trick anwenden.
Diese ganze Technik ließe sich ohne weiteres in ein Standard-Modul (.bas) packen. Dann müssten Sie allerdings das einem Form zugewiesene Region-Handle in dem Form selbst verwalten. Sie müssten es zum richtigen Zeitpunkt löschen - bevor Sie eine neue Region festlegen wollen, wenn Sie die Transparenz aufheben wollen, und erst recht, wenn ein noch transparentes Form entladen werden soll - aber keinesfalls früher! Da Ihr Form aber bestimmt jede Menge anderen Code enthalten wird, erfordert das eine gewisse Disziplin. Sollten Sie versehentlich das Aufräumen der Region-Handles nicht konsequent durchhalten, geht das zu Lasten der System-Ressourcen, solange Ihre Anwendung läuft. Wechseln Sie dann den Transparenz-Zustand eines Forms sehr häufig während der Laufzeit Ihrer Anwendung, kann es, vor allem unter Windows 95, passieren, dass irgendwann keine System-Ressourcen mehr zur Verfügung stehen und ein Windows-Neustart unvermeidbar wird. Zwar heißt es in der MSDN-Dokumentation zu SetWindowRgn, dass das System ein Region-Handle selbst löschen würde, wenn es nicht mehr benötigt wird, aber verlassen sollte man sich darauf nicht
Was liegt also näher, die Technik in einem UserControl zu kapseln, so dass Sie sich auf dem betreffenden Form darauf beschränken können, einfach nur zwischen Transparenz und Nicht-Transparenz hin und her zu schalten? Eigentlich nichts - darum haben wir das auch so realisiert. Und nach dem Motto "Wenn schon, denn schon..." haben wir dabei diesem FormX-OCX ein paar nützliche Modifikationen und Extras hinzugefügt.
Sie brauchen dann nichts weiter zu tun, als einfach das OCX auf dem Form zu platzieren und zur Entwicklungszeit oder zur Laufzeit den gewünschten Transparenz-Modus zu setzen. Um alles andere kümmert sich das Steuerelement automatisch, da es selbst das Form erkennt, auf dem es platziert ist. Diese Technik finden Sie im KnowHow-Tipp Lausch-Eingriffe näher beschrieben. Hier sehen Sie die Anwendung dieses Tipps im ReadProperties-Ereignis des UserControls:
Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
pTransparent = PropBag.ReadProperty("Transparent", fttOpaque)
If Ambient.UserMode Then
With UserControl
If TypeOf .Parent Is Form Then
If Not TypeOf .Parent Is MDIForm Then
Set eForm = .Parent
mFormName = eForm.Name
If pTransparent Then
mFirst = True
End If
End If
End If
End With
End If
End Sub
Die Transparenz-Technik funktioniert nur auf einem einfachen Visual Basic-Form. Für die Verwendung in anderen Containern, wie einem anderen UserControl, einer PropertyPage, einem UserDocument oder gar VB-fremden Containern ist sie nicht ausgelegt. Ebensowenig kann das OCX verwendet werden, um ein MDI-Form transparent zu machen (was auch wenig Sinn hätte). Daher wird zur Laufzeit (Ambient.UserMode = True) geprüft, ob der UserControl.Parent erstens überhaupt ein VB-Form und zweitens kein MDI-Form ist.
Sollte bereits zur Entwicklungszeit eingestellt worden sein, dass das Form von Anfang an nach dem Laden transparent sein soll, muss eine kleine zusätzliche Maßnahme ergriffen werden - darauf werden wir weiter unten noch näher eingehen.
Die Definition der Transparenz-Region schlicht nur von den auf dem Form platzierten Steuerelementen abhängig zu machen, birgt eine kleine Falle in sich. Sollte auf dem Form nämlich kein einziges Steuerelement sichtbar sein, wird das Form komplett unsichtbar. Einerseits kann das ein erwünschtes Resultat sein, es kann aber andererseits auch unerwünscht sein. Das Form kann vom Anwender dann nur noch über das Symbol in der TaskBar geschlossen werden, vorausgesetzt, die Eigenschaft ShowInTaskbar des Forms ist gleich True. Anderenfalls könnte das Form nur noch per Code gezielt geschlossen werden. Ist es das einzige oder letzte Form der Anwendung, wäre diese nicht mehr so einfach zu beenden.
Sie können nun wählen, ob das Form in jedem Fall transparent werden soll, oder nicht, wenn kein sichtbares Steuerelement vorhanden ist. Weiterhin können Sie den Effekt nutzen, ein Form (zu welchem Zweck auch immer) vorübergehend unsichtbar zu machen, während das Symbol in der TaskBar erhalten bleibt. Lassen Sie nämlich ein Form auf konventionelle Weise unsichtbar werden (Form.Hide oder Form.Visible = False), verschwindet dabei auch das Symbol von der TaskBar. Die Eigenschaft Transparent des OCX ist als enumerierter Datentyp definiert:
Public Enum ftTransparentConstants
fttOpaque
fttTransparentIfControls
fttTransparentAlways
fttInvisibleButOnTaskBar
End Enum
Zur Entwicklungszeit wird der der Eigenschaft zugewiesene Wert lediglich in der Variablen pTransparent festgehalten. Eine Auswirkung der Transparent-Setzung soll dagegen nur zur Laufzeit der Anwendung erfolgen - wenn also die UserMode-Eigenschaft des Ambient-Objekts gleich True ist, und wenn sich das OCX mit Sicherheit auf einem VB-Form befindet (eForm ungleich Nothing). Wenn pTransparent gleich fttOpaque (= 0) ist, wird die private Prozedur zMakeIntransparent aufgerufen, in der jegliche Transparenz aufgehoben wird. Bei den drei anderen möglichen Werten wird die eigentliche, private Transparenz-Prozedur zMakeTransparent aufgerufen.
Private pTransparent As ftTransparentConstants
Public Property Get Transparent() As ftTransparentConstants
Transparent = pTransparent
End Property
Public Property Let Transparent(ByVal New_Transparent As _
ftTransparentConstants)
Select Case New_Transparent
Case fttOpaque To fttInvisibleButOnTaskBar
If Ambient.UserMode Then
If eForm Is Nothing Then
pTransparent = fttOpaque
Else
pTransparent = New_Transparent
If pTransparent Then
zMakeTransparent
Else
zMakeIntransparent
End If
End If
Else
pTransparent = New_Transparent
End If
Case Else
Err.Raise 380
End Select
PropertyChanged "Transparent"
End Property
Der Aufwand für die Aufhebung der Transparenz ist versschwindend gering. Wenn ein Region-Handle in der modulweit gültigen Variable mHRgn gespeichert ist, das Form also transparent ist, wird zuerst dieses Handle gelöscht. Anschließend wird (wie weiter oben bereits erwähnt) dem Form (Windows-Fenster) eine Null-Region zugewiesen.
Private Sub zMakeIntransparent()
If mHRgn Then
DeleteObject mHRgn
mHRgn = 0
With eForm
SetWindowRgn .hWnd, 0, True
End With
End If
End Sub
Wesentlich komplexer aufgebaut ist die Prozedur zMakeTransparent.
Private Sub zMakeTransparent()
Dim nXDiff As Long
Dim nYDiff As Long
Dim nOldScaleMode As Integer
Dim nParentRect As RECT
Dim nClientRect As RECT
Dim nMeRect As RECT
Dim nClientXDiff As Long
Dim nClientYDiff As Long
Dim nControl As Control
Dim nControlRect As RECT
Dim nWindowRgn As Long
Dim nControlRgn As Long
Dim nFirstLoop As Boolean
'*** VB 6:
Dim nDummyButton As CommandButton
'*** Alternative für VB 5:
' Dim nHelperControl As Control
' Dim nHelperWnd As Long
' Dim nHelperLeft As Long
' Dim nHelperTop As Long
' Dim nHelperVisible As Boolean
'***
Dim i%
Const RGN_OR = 2&
With eForm
nOldScaleMode = .ScaleMode
If pTransparent <> fttInvisibleButOnTaskBar Then
.ScaleMode = vbPixels
GetWindowRect .hWnd, nParentRect
GetClientRect .hWnd, nClientRect
On Error Resume Next
'*** Alternative für VB 5:
' For Each nHelperControl In .Controls
' nHelperWnd = nHelperControl.hWnd
' If Err.Number Then
' Err.Clear
' Else
' Exit For
' End If
' Next
' If nHelperWnd Then
' With nHelperControl
' nHelperLeft = .Left
' nHelperTop = .Top
' nHelperVisible = .Visible
' .Visible = False
' .Move 0, 0
' GetWindowRect .hWnd, nMeRect
' .Move nHelperLeft, nHelperTop
' .Visible = nHelperVisible
' End With
' Else
' .ScaleMode = nOldScaleMode
' Exit Sub
' End If
'*** Ende VB 5
'*** VB 6:
Do
Err.Clear
Set nDummyButton = eForm.Controls.Add(_
"VB.CommandButton", Ambient.DisplayName & "Dummy" & i)
i = i + 1
Loop While Err.Number
With nDummyButton
.Move 0, 0
GetWindowRect .hWnd, nMeRect
mDummyButtonName = .Name
End With
eForm.Controls.Remove mDummyButtonName
If Err.Number = 365 Then
tmr.Enabled = True
End If
Err.Clear
'*** Ende VB 6
With nParentRect
nClientXDiff = nMeRect.Left - .Left
nClientYDiff = nMeRect.Top - .Top
nXDiff = ((.Right - .Left) - (nClientRect.Right - _
nClientRect.Left)) - nClientXDiff
nYDiff = ((.Bottom - .Top) - (nClientRect.Bottom - _
nClientRect.Top)) '- nClientYDiff
nYDiff = nYDiff - (nYDiff - nClientYDiff)
End With
nFirstLoop = True
On Error GoTo NextControl
For Each nControl In .Controls
With nControl
If Not TypeOf nControl Is Menu Then
If .Container.Name = mFormName Then
If .Visible Then
nControlRect.Left = .Left + nXDiff
nControlRect.Top = .Top + nYDiff
nControlRect.Right = (.Left + .Width) + nXDiff
nControlRect.Bottom = (.Top + .Height) + nYDiff
With nControlRect
nControlRgn = CreateRectRgn(.Left, .Top, .Right, _
.Bottom)
If nFirstLoop Then
nWindowRgn = nControlRgn
nFirstLoop = False
Else
CombineRgn nWindowRgn, nWindowRgn, nControlRgn, _
RGN_OR
DeleteObject nControlRgn
End If
End With
End If
End If
End If
End With
NextControl:
Resume Next
Err.Clear
Next
End If
On Error GoTo 0
If nWindowRgn = 0 Then
Select Case pTransparent
Case fttTransparentAlways, fttInvisibleButOnTaskBar
With nParentRect
nWindowRgn = CreateRectRgn(0, 0, 0, 0)
End With
End Select
End If
If mHRgn Then
DeleteObject mHRgn
End If
mHRgn = nWindowRgn
SetWindowRgn .hWnd, mHRgn, True
.ScaleMode = nOldScaleMode
End With
End Sub
Da die Region-Geschichte unter Windows die Verwendung der Maßeinheit Pixels voraussetzt, versetzen wir das Form vorübergehend während der Abarbeitung dieser Prozedur in den ScaleMode vbPixels. Den zu Beginn angetroffenen ScaleMode sichern wir in nOldScaleMode und restaurieren ihn wieder vor dem Verlassen der Prozedur.
Ist der Transparenz-Modus fttInvisibleButOnTaskbar gewählt, brauchen wir die Regionen der auf dem Form platzierten Steuerelemente nicht zu ermitteln. Anderenfalls ermitteln wir in diesem Zweig die Rechtecke des Forms, des ClientRects und, wie oben beschrieben, mit Hilfe eines kurzzeitig geladenen Dummy-Steuerelements die notwendigen relativen Verschiebungen in X- und Y-Richtung. Falls das Dummy-Steuerelement hier nicht sofort wieder entladen werden konnte, starten wir den Timer, der das Entladen zu einem späteren Zeitpunkt nachholen wird:
Private Sub tmr_Timer()
tmr.Enabled = False
If Len(mDummyButtonName) Then
eForm.Controls.Remove mDummyButtonName
End If
mDummyButtonName = ""
End Sub
Bei jedem Durchlauf der nun folgenden Schleife in zMakeTransparent prüfen wir, ob das gerade bearbeitete Steuerelement aus der Controls-Auflistung des Forms direkt auf diesem platziert ist und nicht auf einem Container-Steuerelement (wie etwa einer PictureBox). Wir prüfen ebenfalls, ob das Steuerelement sichtbar ist. Nur dann ist seine Berücksichtigung sinnvoll - sonst würde eine leere Fläche in der Hintergrundfarbe des Forms erscheinen.
Dann legen wir das Rechteck (ein von Windows benötigter, benutzerdefinierter Datentyp) des Steuerelements fest, indem wir seine Position unter Berücksichtigung der Verschiebungen und seine Größe in dieser Rechteck-Variablen ablegen. Über dieses Rechteck erzeugen wir nun eine Region, deren Handle uns die Funktion CreateRectRgn zurückgibt.
Im ersten Schleifendurchlauf setzen wir diese Region als Gesamtregion für das Form (nWindowRgn). In allen weiteren Durchläufen kombinieren wir die Steuerelement-Region mit der Gesamtregion. Das Ergebnis des Aufrufs der API-Funktion CombineRegion mit dem Flag RGN_OR landet gleich in nWindowRgn (im ersten, dem Rückgabe-Parameter) und steht somit als neue Gesamtregion zur Verfügung. Sollte ein Steuerelement aus irgend einem Grund nicht identifizierbar sein (wenn zum Beispiel dessen Container nicht ermittelt werden kann), überspringen wir es einfach mit Hilfe einer Fehlerbehandlung.
Nun sind wir soweit, die Region dem Form zuweisen zu können. Wurde die Schleife übersprungen, weil das Form per se unsichtbar werden soll, oder wurde kein sichtbares Steuerelement gefunden, enthält die Variable nWindowRgn den Wert 0 - es liegt keine gültige Region vor. Soll das Form entsprechend dem eingestellten Transparenz-Modus dennoch transparent bzw. unsichtbar werden können, erzeugen wir eine leere Region mit keiner Ausdehnung in beide Richtungen.
Wir löschen danach zunächst, falls vorhanden, das alte Region-Handle und weisen dem Form das neue Region-Handle mit SetWindowRgn zu.
Sehen wir uns nun noch die beim Ereignis ReadProperties angesprochene Situation an, wenn das Form gleich nach dem Laden transparent bzw. unsichtbar sein soll. Der relevante Code in ReadProperties lautete:
If pTransparent Then
mFirst = True
End If
Das Problem ist hier, dass nicht garantiert ist, dass alle Steuerelemente auf dem Form bereits geladen sind, wenn unser UserControl das Ereignis ReadProperties empfängt. Wir müssen daher die Ausführung der Transparenz-Setzung genau so lange verzögern, bis wir sicher sein, können, dass alle Steuerelemente geladen sind, und dass auch das Form fertig initialisiert und positioniert worden ist. Dazu setzen wir die modulweit gültige Variable mFirst gleich True. Das eigentliche Setzen der Transparenz sollte jedoch nicht erst dann erfolgen, wenn das Form bereits sichtbar geworden ist. Auch wenn es dann sofort transparent würde, würde das Form entgegen unserer Absicht für kurze Zeit nicht-transparent aufflackern. Wir nutzen daher bei gesetzter Variable mFirst die beiden "abgehörten" Form-Ereignisse eForm_Load (dort schieben wir das noch unsichtbare Form einfach aus dem sichtbaren Bildschirm hinaus und merken uns vorher seine Position) und eForm_Resize, worin wir die Transparenz über die OCX-eigene Refresh-Methode setzen und das Form wieder an seine ursprüngliche Position zurückholen. Danach wird die Variable mFirst gelöscht.
Private Sub eForm_Load()
If mFirst Then
mLeft = eForm.Left
mTop = eForm.Top
eForm.Move -10000, -10000
End If
End Sub
Private Sub eForm_Resize()
With eForm
If .MDIChild Then
If pTransparent Then
Select Case .WindowState
Case vbMinimized
zMakeIntransparent
Case Else
.Refresh
zMakeTransparent
End Select
End If
ElseIf mFirst Then
Me.Refresh
eForm.Move mLeft, mTop
End If
End With
mFirst = False
End Sub
Für den Fall, dass das Form ein MDI-Kindform sein sollte, enthält die Ereignis-Prozedur eForm_Resize eine vorübergehende Rücksetzung der Transparenz, wenn das Form innerhalb der MDI-Umgebung minimiert wird. Ohne diese Rücksetzung würde das minimierte Ablege-Symbol nicht im MDI-Arbeitsbereich erscheinen, da es ebenfalls transparent wäre.
Zu guter Letzt heben wir die Transparenz auf jeden Fall sicherheitshalber im eForm_Unload-Ereignis automatisch auf.
Als kleine Dreingabe haben wir das OCX mit der Fähigkeit versehen, das Form, auf dem es platziert ist, in den Rang eines TopMost-Fensters zu erheben ( Vordergründige Forms). Es kann schon recht praktisch sein, dass ein auf die Fläche einiger weniger Steuerelemente reduziertes Form immer obenauf und somit leichter wiederauffindbar bleibt.
Public Property Get TopMost() As Boolean
TopMost = pTopMost
End Property
Public Property Let TopMost(ByVal New_TopMost As Boolean)
pTopMost = New_TopMost
zTopMost
PropertyChanged "TopMost"
End Property
Private Sub zTopMost()
Const HWND_TOPMOST = -1
Const HWND_NOTOPMOST = -2
Const SWP_NOMOVE = 2
Const SWP_NOSIZE = 1
If Ambient.UserMode Then
If Not (eForm Is Nothing) Then
Select Case pTopMost
Case False
SetWindowPos eForm.hWnd, HWND_NOTOPMOST, _
0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE
Case True
SetWindowPos eForm.hWnd, HWND_TOPMOST, _
0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE
End Select
End If
End If
End Sub
Und nun erfahren Sie auch endlich, wie wir im zu Beginn dieses Artikels dargestellten Beispiel erreicht haben, dass die aufblinkenden Steuerelemente en Bloc so einfach mit der Maus verschoben werden können. Das OCX verfügt nämlich zusätzlich noch über die Methode DragForm, in der wir den in Schiebung!? beschriebenen Tipp anwenden.
Public Sub DragForm()
Const WM_NCLBUTTONDOWN = &HA1
Const HTCAPTION = 2
If Not (eForm Is Nothing) Then
ReleaseCapture
SendMessage eForm.hWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0
End If
End Sub
|