Das gepunktete Rechteck, wie es beispielsweise automatisch in
einem Steuerelement erscheint, das den Fokus inne hat, kennen Sie
bestimmt. Wenn Sie jedoch eigene Steuerelemente auf der Basis eines
UserControls entwickeln wollen, müssen Sie selbst dafür sorgen,
dass der Anwender die Fokusinhaberschaft erkennen kann. Dieses
gepunktete Rechteck, kurz "Fokusrechteck" genannt, können
Sie mittels der API-Funktion DrawFocusRect
zeichnen.
Während in Visual Basic rechteckige Bereiche, wie etwa der eines
Steuerelements, meistens über die Position der linken oberen Ecke
und über die Angaben Breite und Höhe als separate Eigenschaften
beschrieben werden, wird bei API-Funktionen in der Regel die
benutzerdefinierte Datenstruktur RECT
erwartet, in der die Koordinaten der linken oberen und der rechten
unteren Ecke angegeben werden, meistens in der Maßeinheit Pixels:
Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Zum Zeichnen eines Fokusrechtecks rufen Sie die API-Funktion
DrawFocusRect auf, und übergeben ihr den sogenannten Device-Kontext
aus der Eigenschaft hDC (etwa eines UserControls, eines Forms, einer
PictureBox usw.) und eine Variable des Typs RECT, in der Sie die
gewünschten Koordinaten angegeben haben. Denken Sie daran, dass Die
Angabe in Pixels erfolgen muss.
Declare Function DrawFocusRect Lib "user32" _
(ByVal hDC As Long, lpRect As RECT) As Long
Dim FocusRect As RECT
With FocusRect
.Top = 50
.Left = 50
.Bottom = 200
.Right = 200
End With
DrawFocusRect MeineForm.hDC, FocusRect
Das so gezeichnete Fokusrechteck verschwindet jedoch, sobald die
Zeichenfläche aktualisiert wird. Sie müssen es jedes Mal im
Anschluss daran neu zeichnen. Dieses "im Anschluss" daran
ist wichtig, denn nur dann können Sie sich eine interessante
Eigenschaft der Funktion DrawFocusRect zunutze machen. Zeichnen Sie
nämlich das Fokusrechteck erneut an gleicher Stelle darüber, wird
das zuvor gezeichnete Fokusrechteck wieder gelöscht.
DrawFocusRect zeichnet die punktierten Linien des Rechtecks
nämlich nicht in einer bestimmten Farbe, sondern invertiert einfach
an jedem einzelnen Punkt die dort vorhandene Farbe. Ein zweimaliges
Zeichnen an derselben Stelle ergibt damit eine doppelte Invertierung
- der gezeichnete Punkt erscheint wieder in seiner ursprünglichen
Farbe. Daraus ergibt sich logischerweise, dass das Fokusrechteck als
letztes gezeichnet werden muss. Denn würden Sie noch etwas anderes
darüber zeichnen, würde DrawFocusRect unter Umständen beim
nächsten Zeichnen zum Zwecke des Löschens an einzelnen Punkten
eine andere Farbe antreffen und dann diese invertieren - was aber
dort nicht mehr die Ursprungsfarbe ergäbe.
Wenn Sie in einem UserControl die Fokusinhaberschaft darstellen
wollen, ist daher ein wenig mehr Aufwand notwendig, als einfach nur
im GotFocus-Ereignis
ein Fokusrechteck zu zeichnen. Zum einen müssen Sie sicherstellen,
dass das Fokusrechteck jedes Mal nachgezeichnet wird, wenn der
Inhalt des UserControls neu gezeichnet worden ist. Dieses
Neuzeichnen sollte im Ereignis UserControl_Paint erfolgen, und dort
gehört somit als letztes auch ein Aufruf der Funktion DrawFocusRect
hin, wenn das UserControl den Fokus innehat.
Sie können das Fokusrechteck erstmals zeichnen, wenn das
UserControl den Fokus erhält, also in der Ereignisprozedur
UserControl_GotFocus, und es beim Verlust des Fokus in der
Ereignisprozedur UserControl_LostFocus wieder löschen. Falls jedoch
das Steuerelement ähnlich einer Schaltfläche (hier ist es eine
stärkere Umrandung) noch eine weitere Änderung seiner Darstellung
erfordert, sollten Sie die gesamte Zeichnerei in eine separate
private Funktion (z.B. zPaint) verlagern. Diese rufen Sie dann
jeweils von den Ereignissen GotFocus und LostFocus als auch aus dem
Paint-Ereignis auf, prüfen vor dem Aufruf von DrawFocusRect, ob das
UserControl den Focus innehat, und zeichnen das Fokusrechteck nur
dann, wenn dies der Fall ist. Die zuverlässigste Prüfung der
Fokusinhaberschaft nehmen Sie über die API-Funktion GetFocus
vor. Diese gibt ein Fenster-Handle zurück - wenn es identisch mit
dem des UserControls ist (Eigenschaft UserControl.hWnd), hat das
UserControl den Fokus inne. Dann können die besondere Darstellung
der Fokusinhaberschaft und anschließend das Fokusrechteck
gezeichnet werden. Anderenfalls zeichnen Sie den Inhalt des
UserControls in seiner normalen, fokuslosen Darstellung. Der
Einfachheit halber stellen Sie die ScaleMode-Eigenschaft
des UserControls auf vbPixels - dann brauchen Sie nicht ständig
umzurechnen, und auch allgemein tun Sie sich wahrscheinlich leichter
damit bei allen Zeichenvorgängen.
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Declare Function DrawFocusRect Lib "user32" _
(ByVal hdc As Long, lpRect As RECT) As Long
Private Declare Function GetFocus Lib "user32" () As Long
Private Sub UserControl_GotFocus()
zPaint
End Sub
Private Sub UserControl_LostFocus()
zPaint
End Sub
Private Sub UserControl_Paint()
zPaint
End Sub
Private Sub zPaint()
Dim nRect As RECT
Const kDistanceToBorder = 4
With UserControl
If GetFocus() = .hWnd Then
.BackColor = vbWindowBackground
nRect.Left = kDistanceToBorder
nRect.Top = kDistanceToBorder
nRect.Right = .ScaleWidth - kDistanceToBorder
nRect.Bottom = .ScaleHeight - kDistanceToBorder
DrawFocusRect .hdc, nRect
Else
.BackColor = vbButtonFace
End If
End With
End Sub
 |
So kann ein UserControl darstellen, dass es
den Fokus inne hat

|
Eines soll hier allerdings nicht verschwiegen werden. Das
Ereignis LostFocus
wird von der internen Verwaltung in Visual Basic nur ausgelöst,
wenn innerhalb der gleichen Anwendung der Fokus von Ihrem
UserControl zu einem anderen Steuerelement wechselt. Den Wechsel von
einer Anwendung zu einer anderen - und auch den Wechsel zurück -
bekommt Ihr UserControl nicht mit. Um auch in diesem Fall den
Verlust des Fokus darzustellen, müsste Ihr UserControl die
Windows-internen Nachrichten verfolgen können. Dies erfordert
jedoch ein sogenanntes Subclassing des UserControls - das ist jedoch
eine Technik, deren Darstellung den Rahmen dieses Artikels sprengen
würde...
|