ABOUT Visual Basic Programmieren Programmierung Download Downloads Tips & Tricks Tipps & Tricks Know-How Praxis VB VBA Visual Basic for Applications VBS VBScript Scripting Windows ActiveX COM OLE API ComputerPC Microsoft Office Microsoft Office 97 Office 2000 Access Word Winword Excel Outlook Addins ASP Active Server Pages COMAddIns ActiveX-Controls OCX UserControl UserDocument Komponenten DLL EXE
Diese Seite wurde zuletzt aktualisiert am 17.10.1999

Diese Seite wurde zuletzt aktualisiert am 17.10.1999
Aktuell im ABOUT Visual Basic-MagazinGrundlagenwissen und TechnologienKnow How, Tipps und Tricks rund um Visual BasicAddIns für die Visual Basic-IDE und die VBA-IDEVBA-Programmierung in MS-Office und anderen AnwendungenScripting-Praxis für IE, Windows Scripting Host und das Scripting-ControlTools, Komponenten und Dienstleistungen des MarktesRessourcen für Programmierer (Bücher, Job-Börse)Dies&Das...

Themen und Stichwörter im ABOUT Visual Basic-Magazin
Code, Beispiele, Komponenten, Tools im Überblick, Shareware, Freeware
Ihre Service-Seite, Termine, Job-Börse
Melden Sie sich an, um in den vollen Genuss des ABOUT Visual Basic-Magazins zu kommen!
Informationen zur AVB-Web-Site, Kontakt und Impressum

Zurück...

Zurück...

Von Jürgen Thümmler/-hg mailto:hg_formxmarqueetooltips@aboutvb.de

Freischwebende Buttons über dem Desktop - diesen und noch ein paar weitere Form-Effekte bietet das Steuerelement FormX (Forms mit Durchblick und mehr - Code zu Beispiel-Projekt 2Beispiel-Projekt 2)

Buttons - freischwebend über dem Desktop... Ein interessanter Effekt ist das, nicht wahr?

Ganz einfach, werden Sie sagen, die Buttons werden mit der API-Funktion MSDN-Library - SetParentSetParent 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 MSDN-Library - CreateRectRgnCreateRectRgn in Regionen. Dann kombinieren wir diese Regionen so, dass sie sich gegenseitig ausschließen (API-Funktion MSDN-Library - CombineRgnCombineRgn mit RGN_OR) und übertragen zum Schluss die Ergebnis-Region mit MSDN-Library - SetWindowRgnSetWindowRgn 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 MSDN-Library - GetWindowRectGetWindowRect 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 MSDN-Library - GetClientRectGetClientRect 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 MSDN-Library - SetWindowRgnSetWindowRgn, 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


Code des Controls FormX Code des Controls FormX
Code des Beispielprojekts 1 Code des Beispiel-Projekts avbFormXTest (Beispiel1)
Code des Beispielprojekts 2 Code des Beispiel-Projekts avbFormXTest2

Projekt avbFormXOCX und Beispiel-Projekte (frmxcode.zip - ca. 10,1 KB)

ActiveX-Control als Setup (ohne VB 6-Runtime!) (frmxocxs.zip - ca. 273 KB)



Komponenten-Übersicht

Zum Seitenanfang

Copyright © 1999 - 2023 Harald M. Genauck, ip-pro gmbh  /  Impressum

Zum Seitenanfang

Zurück...

Zurück...