Wenn der Inhalt eines Fensters (Form, PictureBox, UserControl usw.) von Ihrem Programm selbst gezeichnet wird und dabei umfangreiche Zeichenoperationen anfallen, kann erübrigen sich diese Operationen teilweise oder völlig, wenn das Fenster zum Teil oder völlig von anderen Fenstern überdeckt wird.
Zum Testen einer Überdeckung ziehen wir die Clipping-Funktionen ("Clipping", zu Deutsch in etwa: "Beschnitt", "Zuschnitt") des Windows-GDI-APIs heran. Jedes Fenster kann in der Regel die Fläche seines Rechtecks nach Belieben selbst bemalen. Die erste und häufigste Abweichung von dieser Regel wendet Windows selber an, um den Darstellungsbereich eines teilweise verdeckten Fensters (oder Steuerelements, das ja auch ein Fenster ist) zu beschneiden, so dass dieses bei der Selbstdarstellung nicht in den Bereich des überdeckenden Fensters hinein malt. Ein solcher beschnittener Bereich wird "Region" genannt. Eine solche Region braucht noch nicht einmal rechteckig zu sein - denken Sie etwa an zwei versetzt mit etwas Abstand zueinander liegende Fenster, die ein drittes, dahinter liegendes Fenster teilweise überdecken. Selbst Fenster mit völlig unregelmäßigen und kurvigen Konturen sind möglich (etwa in Form eines Puzzle-Steines). Solche Regions (ja, es handelt sich hier um den englischsprachigen Begriff, daher diese Form des Plurals) können nach Bedarf erstellt und einem Geräte-Kontext (in dem die API-Zeichenvorgänge stattfinden) zugewiesen werden. Eine Region kann aber auch einem Fenster direkt zugewiesen werden und somit eine absolute, äußere Kontur für das Fenster dauerhaft festlegen.
Zur Prüfung der Überdeckung beschränken wir uns der Einfachheit halber auf einen Vergleich des Rechtecks eines Fensters mit dem umschließenden Rechteck der aktuellen Clipping-Region eines Fensters. Das Rechteck des Fensters liefert uns die API-Funktion GetClientRect und das die Clipping-Region umschließende Rechteck erhalten wir von der API-Funktion GetClipBox. Ob diese beiden Rechtecke übereinstimmen, sagt uns die API-Funktion EqualRect. Zusätzlich liefert uns der Aufruf von GetClipBox noch die Information, ob die aktuelle Clipping-Region ein einfaches Rechteck ist, oder ob sie durch teilweise Überdeckung des Fensters eine "komplexe" Region ist.
Diese Auswertungen zusammen übernimmt die folgende Hilfsfunktion WindowVisible, der sie das Fenster-Handle (hWnd) des betroffenen Fensters und dessen Geräte-Kontext (hDC) übergeben. Als Rückgabewert erhalten Sie einen Wert aus der Enumeration WindowVisibleConstants, der besagt, ob das Fenster völlig, teilweise oder gar nicht sichtbar ist.
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Declare Function EqualRect Lib "user32" _
(lpRect1 As RECT, lpRect2 As RECT) As Long
Private Declare Function GetClientRect Lib "user32" _
(ByVal hWnd As Long, lpRect As RECT) As Long
Private Declare Function GetClipBox Lib "gdi32" _
(ByVal hDC As Long, lpRect As RECT) As Long
Public Enum WindowVisibleConstants
wvHidden
wvPartialVisible
wvCompleteVisible
End Enum
Public Function WindowVisible(hWnd As Long, ByVal hDC As Long) _
As WindowVisibleConstants
Dim nClientRect As RECT
Dim nClipRect As RECT
Dim nTestClip As Long
Dim nTestEqual As Boolean
Const NULLREGION = 1
Const SIMPLEREGION = 2
Const COMPLEXREGION = 3
GetClientRect hWnd, nClientRect
nTestClip = GetClipBox(hDC, nClipRect)
nTestEqual = CBool(EqualRect(nClientRect, nClipRect))
Select Case nTestClip
Case COMPLEXREGION
WindowVisible = wvPartialVisible
Case SIMPLEREGION
If nTestEqual Then
WindowVisible = wvCompleteVisible
Else
WindowVisible = wvPartialVisible
End If
Case NULLREGION
WindowVisible = wvHidden
End Select
End Function
Die folgende Variante dieser Funktion WindowVisibleObj unterscheidet sich lediglich dadurch, dass Sie der Einfachheit halber ein Fenster oder Steuerelement als Objekt übergeben können, wenn dieses über die Eigenschaften hWnd und hDC verfügt.
Public Function WindowVisibleObj(Object As Object) _
As WindowVisibleConstants
Dim nClientRect As RECT
Dim nClipRect As RECT
Dim nTestClip As Long
Dim nTestEqual As Boolean
Const NULLREGION = 1
Const SIMPLEREGION = 2
Const COMPLEXREGION = 3
With Object
GetClientRect .hWnd, nClientRect
nTestClip = GetClipBox(.hDC, nClipRect)
End With
nTestEqual = CBool(EqualRect(nClientRect, nClipRect))
Select Case nTestClip
Case COMPLEXREGION
WindowVisibleObj = wvPartialVisible
Case SIMPLEREGION
If nTestEqual Then
WindowVisibleObj = wvCompleteVisible
Else
WindowVisibleObj = wvPartialVisible
End If
Case NULLREGION
WindowVisibleObj = wvHidden
End Select
End Function
Zur Prüfung, ob sich ein bestimmter Punkt oder ein bestimmter rechteckiger Bereich des Fensters innerhalb der aktuellen Clipping-Region befindet, also sichtbar ist, können Sie die API-Funktionen PointVisible (als Alias von ursprünglich "PtVisible") und RectVisible direkt verwenden:
Public Declare Function PointVisible Lib "gdi32" _
Alias "PtVisible" (ByVal hDC As Long, ByVal x As Long, _
ByVal y As Long) As Long
Public Declare Function RectVisible Lib "gdi32" _
(ByVal hDC As Long, lpRect As RECT) As Long
|