Kontakt
DSVGO
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