Visual Basic - Technik, FAQ, Tricks, Beispiele

Home / Objekte / Form / Beschränkung

Formular-Größe beschränken

Einleitung

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).

Konventionelle Lösung mit Form_Resize

Voraussetzung

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
Code / Quelltext

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

Lösung mit Subclassing

Voraussetzung

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.

Idee

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
Code / Quelltext

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! Smile!

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