VB-Tec.de Visual Basic - Technik, FAQ, Tricks, BeispieleHome / Objekte / Form / Beschränkung Formular-Größe beschränken |
VB bietet leider keine eingebaute Möglichkeit, die Größe eines Formulars zu beschränken. Natürlich könnte man im Form_Resize-Ereignis entsprechende Abfragen einbauen, so dass "unerlaubte" Größen nachträglich ignoriert werden. Allerdings entsteht dadurch ein sehr unschöner Flacker-Effekt.
Ein komplettes Beispiel ist übrigens in folgendem Zip-Archiv zu finden: formsize.zip (5 KB).
Die minimale und maximale Größe des Formulars wird in folgender Struktur abgelegt:
Private Type typFormSizes MinWidth As Long MinHeight As Long MaxWidth As Long MaxHeight As Long End Type Private FormSizes As typFormSizes
Beim Laden des Formulars wird die Struktur mit den gewünschten Werten gefüllt: Das Formular soll nur in der Breite auf maximal 200% vergrößert werden, die Höhe soll nicht veränderbar sein.
Private Sub Form_Load()
With FormSizes
.MinWidth = Width
.MaxWidth = .MinWidth * 2 'maximal 200%
.MinHeight = Height
.MaxHeight = .MinHeight
End With
End Sub
Die folgende Lösung ist zwar einfach, aber führt zu unschönen Effekten: Einfach mal ausprobieren...
Private Sub Form_Resize()
If Me.WindowState = vbNormal Then
With FormSizes
Select Case Width
Case Is < .MinWidth: Width = .MinWidth
Case Is > .MaxWidth: Width = .MaxWidth
End Select
Select Case Height
Case Is < .MinHeight: Height = .MinHeight
Case Is > .MaxHeight: Height = .MaxHeight
End Select
End With
End If
End Sub
Die folgende Lösung ist zwar aufwändiger, führt dafür aber zu einer befriedigenden Darstellung (d.h. ganz ohne Flackerei). Es wird dafür die in "Was ist SubClassing - und wie nutzt man es?" vorgestellte "Komponente" benötigt.
Die Idee dahinter ist folgende: Vor einer Größenänderung fragt Windows mittles der WM_GETMINMAXINFO-Nachricht die erlaubte Größe des Formulars ab. Dazu wird in lParam die Adresse einer sogenannten MINMAXINFO-Struktur mitgegeben. Mit einem Offset von 24 Bytes (die POINTAPI-Struktur enthält zwei Longs) sind die gewünschten Werte zu finden:
'Nur zur Dokumentation: Private Type MINMAXINFO ptReserved As POINTAPI ptMaxSize As POINTAPI ptMaxPosition As POINTAPI ptMinTrackSize As POINTAPI '24 Bytes Offset ptMaxTrackSize As POINTAPI ' End Type
Im Deklarationsteil müssen (zusätzlich zur o.g. FormSizes) die bekannte API-Routine RtlMoveMemory sowie die SubClassing-Komponente bekanntgemacht werden:
Private Declare Sub RtlMoveMemory Lib "kernel32" ( _
dest As Any, source As Any, ByVal bytes As Long)
Private WithEvents Msg As MsgHook 'SubClassing-Objekt
Private Type typFormSizes
MinWidth As Long
MinHeight As Long
MaxWidth As Long
MaxHeight As Long
End Type
Private FormSizes As typFormSizes
In Form_Load wird wie gehabt die Größen-Struktur gefüllt (allerdings in Windows-genehmen Pixeln umgerechnet). Ausserdem wird der SubClassing-Komponente mitgeteilt, auf welche Nachricht sie überhaupt reagieren soll:
Private Sub Form_Load()
With FormSizes
.MinWidth = Width / Screen.TwipsPerPixelX
.MaxWidth = .MinWidth * 2
.MinHeight = Height / Screen.TwipsPerPixelY
.MaxHeight = .MinHeight
End With
Set Msg = New MsgHook
Msg.Hook Me.hWnd, WM_GETMINMAXINFO
End Sub
Die Form_Resize-Prozedur wird nicht mehr benötigt, muss also gelöscht werden (schließlich wollen wir ja kein Flackern mehr):
Private Sub Form_Resize() 'Nicht benötigt. End Sub
Die eigentliche Arbeit geschieht im SubClassing-Ereignis Before: Die erlaubten Formulargrößen werden mit RtlMoveMemory in einem Rutsch in die (hier unsichtbare) MINMAXINFO-Struktur geschrieben, sowie die Nachrichten- Weiterleitung unterbunden.
Private Sub Msg_Before(uMsg As Long, wParam As Long, lParam As Long, retVal As Long)
If Me.WindowState = vbNormal Then
RtlMoveMemory ByVal lParam + 24, FormSizes, Len(FormSizes)
uMsg = 0 'Nachricht "stornieren"
End If
End Sub
So, das war es auch schon!
Nach dem Speichern kann das neue Verhalten getestet werden: Das ist doch deutlich schöner, nicht wahr?
© Jost Schwider, 18.10.2001-18.10.2001 - http://vb-tec.de/formsize.htm