Flexible Formular Eigenschaften
Schreibgeschützte Form Eigenschaften, wie MinButton oder MaxButton zur Laufzeit ändern
War es Faulheit oder sah man einfach nur keine Notwendigkeit, die Eigenschaften MinButton, MaxButton und Borderstyle eines Formulars zur Laufzeit ändern zu können? Fest steht, es geht - sogar für MDI Formulare, die derartige Eigenschaften nicht mal zur Design-Zeit bieten.
Zur Design- Zeit können Sie nahezu alle Form Eigenschaften, wie BorderStyle fest oder änderbar, MinButton und MaxButton sichtbar oder nicht, festlegen. Einige Programmabläufe erfordern allerdings eine Änderung dieser Eigenschaften zur Laufzeit, doch hier unterbindet VB den schreibenden Zugriff. MDI Formulare bieten diese Eigenschaften weder zur Design-Zeit noch zur Laufzeit. Ein Zugriff auf den Zustand des Schließen- Menüs bieten beide Formulartypen nicht. Mit ein paar API Funktion kann diese Einschränkung jedoch umgangen werden, auch für MDI Formulare.
Die benötigten API Deklarationen und Konstanten:
Private Declare Function GetSystemMenu Lib "user32" _ (ByVal hWnd As Long, ByVal bRevert As Long) As Long Private Declare Function GetMenuItemCount Lib "user32" _ (ByVal hMenu As Long) As Long Private Declare Function RemoveMenu Lib "user32" _ (ByVal hMenu As Long, ByVal nPosition As Long, ByVal wFlags As Long) As Long Private Declare Function DrawMenuBar Lib "user32" _ (ByVal hWnd As Long) As Long Private Const MF_BYCOMMAND = &H0& Private Const SC_CLOSE = &HF060 Private Const SC_MAXIMIZE = &HF030 Private Const SC_MINIMIZE = &HF020 Private Const SC_MOVE = &HF010 Private Const SC_RESTORE = &HF120 Private Const SC_SIZE = &HF000 Private Declare Function GetWindowLong Lib "user32" _ Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long Private Declare Function SetWindowLong Lib "user32" _ Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, _ ByVal dwNewLong As Long) As Long Private Const GWL_STYLE = (-16) Private Const WS_MAXIMIZEBOX = &H10000 Private Const WS_MINIMIZEBOX = &H20000 Private Const WS_THICKFRAME = &H40000
Die Schaltflächen in der Titelleiste des Formulars werden durch das Entfernen der entsprechenden Fensterstile WS_MAXIMIZEBOX bzw. WS_MINIMIZEBOX ausgeblendet. Für den Rahmen ist der Fensterstil WS_THICKFRAME zuständig. Wird er entfernt, hat das Fenster einen unveränderbaren Rahmen. Den aktuellen Fensterstil ermittelt die API Funktion GetWindowLong. GWL_STYLE gibt dabei an, das die einfachen Fensterstile ermittelt werden sollen. SetWindowLong weist den veränderten Fensterstil wieder zu.
Damit der Anwender diese Fensterstile nicht Mithilfe des Systemmenüs übergehen kann, müssen hier noch die entsprechenden Einträge entfernt werden. Den Handle des Systemmenüs ermittelt man mit der Funktion GetSystemMenu, die Menüeinträge werden mit der RemoveMenu- Funktion entfernt. Damit man nicht blind im Menü herumstochern muss und wahllos Einträge löscht, gibt man für den Parameter nPosition die dem Eintrag zugeordnete System Command - Konstante an. Zum Schluß informiert man das Fenster von der Änderung des Systemmenüs, mittels der DrawMenuBar- Funktion. Ggf. sorgt diese auch zugleich für das Aktualisieren des geänderten Rahmen.
Die Prozedur DynamicSysMenu isoliert alle API Aufrufe und erledigt das Beiwerk. In Ihrem Projekt eingesetzt, brauchen Sie nur noch das entsprechende Form- Objekt übergeben und legen fest, welche Funktionen des Systemmenüs deaktiviert werden soll. Übergeben Sie nur das Form- Objekt, wird das Systemmenü in den Ausgangszustand zurückgesetzt
.Public Sub DynamicSysMenu(ByVal Form As Form, _ Optional ByVal NoMin As Boolean, _ Optional ByVal NoMax As Boolean, _ Optional ByVal NoClose As Boolean, _ Optional ByVal NoSize As Boolean) Dim hMenu As Long Dim lngStyle As Long Dim bolMin As Boolean Dim bolMax As Boolean Dim bolSize As Boolean With Form GetSystemMenu .hWnd, True lngStyle = GetWindowLong(.hWnd, GWL_STYLE) hMenu = GetSystemMenu(.hWnd, False) If Not TypeOf Form Is MDIForm Then bolMin = (((.BorderStyle = vbSizable) Or _ (.BorderStyle = vbFixedSingle)) _ And .MinButton And (Not NoMin)) bolMax = (((.BorderStyle = vbSizable) Or _ (.BorderStyle = vbFixedSingle)) _ And .MaxButton And (Not NoMax)) bolSize = (((.BorderStyle = vbSizable) Or _ (.BorderStyle = vbSizableToolWindow)) And _ (Not NoSize)) Else bolMin = Not NoMin bolMax = Not NoMax bolSize = Not NoSize End If End With '// Zugesicherte Fensterstile wiederherstellen: If (bolMax) Then lngStyle = lngStyle Or WS_MAXIMIZEBOX If (bolMin) Then lngStyle = lngStyle Or WS_MINIMIZEBOX If (bolSize) Then lngStyle = lngStyle Or WS_THICKFRAME '// Überflüssige Menüeinträge entfernen: If Not (bolSize) Then RemoveMenu hMenu, SC_SIZE, MF_BYCOMMAND If Not (bolMin) Then RemoveMenu hMenu, SC_MINIMIZE, MF_BYCOMMAND If Not (bolMax) Then RemoveMenu hMenu, SC_MAXIMIZE, MF_BYCOMMAND If ((Not bolMin) And (Not bolMax)) Then RemoveMenu hMenu, SC_RESTORE, MF_BYCOMMAND If Not (Form.Moveable) Then RemoveMenu hMenu, SC_MOVE, MF_BYCOMMAND If GetMenuItemCount(hMenu) = 2 Then RemoveMenu hMenu, &H0, MF_BYCOMMAND If (NoClose) Then RemoveMenu hMenu, SC_CLOSE, MF_BYCOMMAND RemoveMenu hMenu, &H0, MF_BYCOMMAND End If '// Ggf. Schaltflächen ausblenden und Borderstyle ändern: If Not (bolMax) Then lngStyle = lngStyle And Not WS_MAXIMIZEBOX If Not (bolMin) Then lngStyle = lngStyle And Not WS_MINIMIZEBOX If Not (bolSize) Then lngStyle = lngStyle And Not WS_THICKFRAME With Form '// Neuen Fensterstil zuweisen/ Menü aktualisieren: SetWindowLong .hWnd, GWL_STYLE, lngStyle DrawMenuBar .hWnd End With End Sub
Zwei Hinweise zum Schluss:
- Alle Eigenschaften, die man zur Laufzeit verändern möchte, müssen schon zur Design- Zeit festgelegt werden.
- Das Deaktivieren von "Schließen" verhindert nicht das Beenden durch die Tastenkombination <ALT>+<F4>. Hierzu muss im QueryUnload Ereignis des Form das Beenden mittels Cancel = True verhindert werden.
- modDynamicSysMenu Modul und Beispielprojekt (dynsysmenu.zip - 4 KB)