Seit Windows 95 können Fenster einen Griff haben. Nein, nicht jenen berüchtigten zum Wegschmeißen, sondern ein kleines, geriffelt erscheinendes Dreieck in der rechten, unteren Ecke, das gewissermaßen als "Verlängerung" der Ecke zum Ändern der Größe dient.
Genaugenommen ist es eigentlich ein kleines Quadrat, dessen Größe von der systemweiten Einstellung der Rollbalkengröße abhängt. Es ist genauso breit wie ein vertikaler Rollbalken und genauso hoch, wie ein horizontaler Rollbalken.
Eine Möglichkeit, ein Visual Basic-Form mit einer solchen Griffecke zu versehen, ist die Verwendung eines Statusbar-Steuerelements aus den CommonControls. Wird dieses fest an der Unterkante des Forms platziert (Align = 2 - Unten ausrichten), erscheint automatisch die Griffecke.
Alternativ dazu können Sie auch das hier vorgestellte Steuerelement SizeGrip verwenden. Zur Laufzeit sorgt es automatisch für seine Positionierung in der rechten, unteren Ecke und sitzt gegebenenfalls (Eigenschaft AutoZOrder = True) vor allen anderen Steuerelementen auf dem Form. Ebenso passt es selbstständig seine Größe der systemweiten Einstellung der Rollbalkengröße an.
Die automatische Positionierung beruht auf der in Lausch-Eingriffe vorgestellten Technik und kann wegen der festen Typbindung nur auf einem VB-Standard-Form eingesetzt werden.
Private mForm As Form
Private WithEvents eForm As Form
Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
' ...
With UserControl
If TypeOf .Parent Is Form Then
If Not TypeOf .Parent Is MDIForm Then
Set mForm = .Parent
If Ambient.UserMode Then
Set eForm = mForm
End If
End If
End If
End With
End Sub
Der Aufruf der Systemfunktion zur Größenänderung ähnelt der in Schiebung?! vorgestellten Technik - hier wird als Systemkonstante statt HTCAPTION die Konstante HTBOTTOMRIGHT über die API-Funktion SendMessage versandt.
Private Declare Function ReleaseCapture Lib "user32" () As Long
Private Declare Function SendMessage Lib "user32" _
Alias "SendMessageA" (ByVal Hwnd As Long, _
ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) _
As Long
Private Sub zSize(ByVal iHwnd As Long)
Const WM_NCLBUTTONDOWN = &HA1
Const HTBOTTOMRIGHT = 17
ReleaseCapture
SendMessage iHwnd, WM_NCLBUTTONDOWN, HTBOTTOMRIGHT, 0
End Sub
Damit das Steuerelement eine Änderung der Rollbalkengröße durch den Anwender mitbekommt und diese daraufhin nachvollziehen kann, wird im UserControl_Paint-Ereignis jedes Mal die Ereignis-Prozedur des UserControl_Resize-Ereignisses aufgerufen und seine Darstellung mit Hilfe der API-Funktion DrawFrameControl neu gezeichnet.
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Declare Function DrawFrameControl Lib "user32" _
(ByVal hDC As Long, lpRect As RECT, ByVal nCtlType As Long, _
ByVal nFlags As Long) As Long
Private Sub UserControl_Paint()
Dim nRect As RECT
Const DFC_SCROLL = 3
Const DFCS_SCROLLSIZEGRIP = &H8
Static sInProc As Boolean
If sInProc Then
Exit Sub
Else
sInProc = True
End If
UserControl_Resize
With UserControl
nRect.Right = .ScaleWidth
nRect.Bottom = .ScaleHeight
DrawFrameControl .hDC, nRect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP
If Not Ambient.UserMode Then
UserControl.Line (0, 0)-(.ScaleWidth - 1, .ScaleHeight - 1), _
vbBlack, B
End If
End With
sInProc = False
End Sub
In der Ereignis-Prozedur des UserControl_Resize-Ereignisses wird zunächst das Steuerelement über die ZOrder-Eigenschaft des Extender-Objekts gegebenenfalls in den Vordergrund vor alle anderen Steuerelemente des Eltern-Forms gesetzt.
Danach werden die aktuellen Rollbalken-Maße über die API-Funktion GetSystemMetrics ermittelt. Sollten sich diese geändert haben, werden sie in den modulweit gültigen Variablen pVScrollWidth und pHScrollHeight festgehalten und es wird die Änderung vermerkt (nChanged = True). Zur Laufzeit werden die Positionierung und die Größe des Steuerelements nachgeführt, wenn es sich auf einem VB-Standard-Form befindet. Ist dies nicht der Fall, wird lediglich die Größe an die Rollbalken-Abmessungen angepasst. Zur Designzeit geschieht immer nur letzteres. Abschließend wird die Darstellung des Steuerelements über den Aufruf von UserControl_Paint aufgefrischt.
Als kleines Abfallprodukt wird nun noch bei einer vermerkten Änderung der Rollbalken-Abmessungen das steuerelementeigene Ereignis ScrollbarSizeChanged ausgelöst. Die Rollbalken-Abmessungen können außerdem auch jederzeit über die Eigenschaften VScrollWidth und HScrollHeight abgefragt werden.
Weil sich die beiden Ereignis-Prozeduren UserControl_Paint und UserControl_Resize jeweils gegenseitig aufrufen, wird in beiden eine mehrfache vollständige Ausführung blockiert ( Aller guten Dinge ist eins), damit keine endlose Rekursion entsteht.
Private Declare Function GetSystemMetrics Lib "user32" _
(ByVal nIndex As Long) As Long
Public Event ScrollbarSizeChanged(ByVal VScrollWidth As Long, _
ByVal HScrollHeight As Long)
Private Sub UserControl_Resize()
Dim nVScrollWidth As Long
Dim nHScrollHeight As Long
Dim nChanged As Boolean
Dim nWidth As Single
Dim nHeight As Single
Const SM_CXVSCROLL = 2
Const SM_CYHSCROLL = 3
Static sInProc As Boolean
If sInProc Then
Exit Sub
Else
sInProc = True
End If
On Error Resume Next
If pAutoZOrder Then
Extender.ZOrder 1
End If
nVScrollWidth = GetSystemMetrics(SM_CXVSCROLL)
nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL)
If CBool(nVScrollWidth <> pVScrollWidth) _
Or CBool(nHScrollHeight <> pHScrollHeight) Then
pVScrollWidth = nVScrollWidth
pHScrollHeight = nHScrollHeight
nChanged = True
End If
If Ambient.UserMode Then
If mForm Is Nothing Then
UserControl.Size pVScrollWidth * Screen.TwipsPerPixelX, _
pHScrollHeight * Screen.TwipsPerPixelY
Else
With mForm
nWidth = .ScaleX(pVScrollWidth, vbPixels, .ScaleMode)
nHeight = .ScaleY(pHScrollHeight, vbPixels, .ScaleMode)
Extender.Move .ScaleWidth - nWidth, _
.ScaleHeight - nHeight, nWidth, nHeight
End With
End If
Else
UserControl.Size pVScrollWidth * Screen.TwipsPerPixelX, _
pHScrollHeight * Screen.TwipsPerPixelY
End If
UserControl_Paint
If nChanged Then
RaiseEvent ScrollbarSizeChanged
End If
sInProc = False
End Sub
Da es wenig Sinn macht, dass das Steuerelement den Fokus bekommen kann, setzen Sie die Eigenschaft CanGetFocus des UserControls gleich False.
Sollte das Steuerelement auf einem anderen Container als einem VB-Standard-Form platziert sein, erfolgt keine automatische Positionierung in der rechten unteren Ecke des Containers, sondern nur die Größenanpassung. Außerdem werden lediglich die Mausereignisse des UserControls über die Ereignisse MouseDown, MouseMove und MouseUp nach außen weitergereicht. Dann kann extern bestimmt werden, für welches Fenster die Größenänderung stattfinden soll, und dessen Fenster-Handle an die separate und unabhängige Methode DoSize übergeben werden. Diese Methode ruft ebenfalls die bereits oben beschriebene private Methode zur Größenänderung über die API-Message auf.
Public Event MouseDown(Button As Integer, Shift As Integer, _
X As Single, Y As Single)
Public Event MouseMove(Button As Integer, Shift As Integer, _
X As Single, Y As Single)
Public Event MouseUp(Button As Integer, Shift As Integer, _
X As Single, Y As Single)
Private Sub UserControl_MouseDown(Button As Integer, _
Shift As Integer, X As Single, Y As Single)
If mForm Is Nothing Then
RaiseEvent MouseDown(Button, Shift, X, Y)
Else
Select Case Button
Case vbLeftButton
zSize mForm.Hwnd
End Select
End If
End Sub
Private Sub UserControl_MouseMove(Button As Integer, _
Shift As Integer, X As Single, Y As Single)
RaiseEvent MouseMove(Button, Shift, X, Y)
End Sub
Private Sub UserControl_MouseUp(Button As Integer, _
Shift As Integer, X As Single, Y As Single)
RaiseEvent MouseUp(Button, Shift, X, Y)
End Sub
Public Sub DoSize(ByVal AnyHwnd As Long)
zSize AnyHwnd
End Sub
Weil das Steuerelement nur aus einem Modul besteht, brauchen Sie nicht unbedingt eine als OCX kompilierte Version zu verwenden. Sie können die UserControl-Datei SizeGrip.ctl auch direkt in ein Projekt aufnehmen. In diesem Fall sollten Sie die Datei SizeGrip.ctl und deren binäre Zusatzdatei SizeGrip.ctx im Ordner ...\Template\Userctls Ihres Visual Basic-Ordners ablegen. Dann können Sie das Steuerelement als Vorlage wiederverwenden und direkt im Einfügen-Dialog auswählen.

|