ABOUT Visual Basic Programmieren Programmierung Download Downloads Tips & Tricks Tipps & Tricks Know-How Praxis VB VBA Visual Basic for Applications VBS VBScript Scripting Windows ActiveX COM OLE API ComputerPC Microsoft Office Microsoft Office 97 Office 2000 Access Word Winword Excel Outlook Addins ASP Active Server Pages COMAddIns ActiveX-Controls OCX UserControl UserDocument Komponenten DLL EXE
Diese Seite wurde zuletzt aktualisiert am 09.05.2003

Diese Seite wurde zuletzt aktualisiert am 09.05.2003
Aktuell im ABOUT Visual Basic-MagazinGrundlagenwissen und TechnologienKnow How, Tipps und Tricks rund um Visual BasicActiveX-Komponenten, Controls, Klassen und mehr...AddIns für die Visual Basic-IDE und die VBA-IDEVBA-Programmierung in MS-Office und anderen AnwendungenScripting-Praxis für den Windows Scripting Host und das Scripting-ControlTools, Komponenten und Dienstleistungen des MarktesRessourcen für Programmierer (Bücher, Job-Börse)Dies&Das...

Themen und Stichwörter im ABOUT Visual Basic-Magazin
Code, Beispiele, Komponenten, Tools im Überblick, Shareware, Freeware
Ihre Service-Seite, Termine, Job-Börse
Melden Sie sich an, um in den vollen Genuss des ABOUT Visual Basic-Magazins zu kommen!
Informationen zum ABOUT Visual Basic-Magazin, Kontakt und Impressum

Zurück...

Modales Versteckspiel

Zurück...


Anzeige

(-hg) mailto:hg_modalhide@aboutvb.de

Offensichtlich ist es nicht möglich, ein modal angezeigtes Form zu verbergen, ohne die Modalität aufzuheben. Denn es reicht schon das Verbergen durch den Aufruf der Hide-Methode oder durch das Setzen der Visible-Eigenschaft auf False, um die Modalität aufzuheben, so dass der dem modalen Show-Aufruf folgenden Code weiter ausführt wird.

Ein Szenario für ein nicht sichtbares, aber dennoch modales Form wäre etwa ein "Abbrechen"-Form während der Ausführung eines länger andauernden Vorgangs, das erst ab einer bestimmten Dauer des Vorgangs sichtbar werden, anderenfalls jedoch gar nicht erst angezeigt werden und den Anwender somit auch nicht "belästigen" soll.

Eine triviale Möglichkeit der Lösung wäre, das eigentlich doch angezeigte Form vorübergehend aus dem Bildschirm hinaus zu schieben:

Me.Move Screen.Width, Screen.Height

Doch angesichts von Mehrfachbildschirmen und Tools und Grafik-Treibern zur Organisation von virtuellen Bildschirmen ist das womöglich keine gute Idee: Das modale Form könnte damit einfach bloß auf einen anderen "Bildschirm" verschoben werden.

Eine andere, elegantere Möglichkeit bietet das Windows-API mit der Funktion SetWindowRgn. Über diese Funktion können Sie die sichtbare Fläche eines Fensters (Forms) auf Null schrumpfen lassen. Es wird augenscheinlich unsichtbar - aber genau genommen wird es transparent. Aus der Sicht der Windows- und VB-internen Verwaltung bleibt es jedoch "sichtbar", d.h. der Visible-Status bleibt unberührt - und damit bleibt auch die Modalität unberührt.

Die Funktion SetWindowRgn erwartet eine so genannte "Region", die Sie mit der API-Funktion CreateRectRgn anlegen können. Nebenbei bemerkt: CreateRectRgn erzeugt eine rechteckige Region. Sie können zwar auch komplex geformte Regionen mit SetWindowRgn verwenden, doch die einfacher anzulegende rechteckige Region reicht vollauf für unseren Zweck. Da das Rechteck (die Fläche) der anzulegenden Region keine Ausdehnung haben soll, übergeben Sie der Funktion in allen Parametern den Wert 0:

Private Declare Function CreateRectRgn Lib "gdi32" _
 (ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, _
 ByVal Y2 As Long) As Long
Private Declare Function SetWindowRgn Lib "user32" _
 (ByVal hWnd As Long, ByVal hRgn As Long, _
 ByVal Redraw As Boolean) As Long

Dim nRgn As Long
nRgn = CreateRectRgn(0, 0, 0, 0)

Diese Region übergeben Sie nun der Funktion SetWindowRgn zusammen mit dem Fenster-Handle (Eigenschaft hWnd) des modal angezeigten Forms:

SetWindowRgn Me.hWnd, nRgn, True

- und das modale Form ist tatsächlich unsichtbar.

Um das Form nun doch sichtbar werden zu lassen, übergeben Sie anstelle einer Region einfach den Wert 0 (eine "Null-Region"):

SetWindowRgn Me.hWnd, 0, True

- und das modale Form wird (wieder) sichtbar.

Der letzte Parameter, in dem Sie den Wert True übergeben, sorgt dafür, dass Windows die Änderung der Region sofort nachhält und darstellt.

Um eine Kleinigkeit müssen wir uns nun aber noch kümmern. Die tatsächliche Unsichtbarkeit eines Fensters bringt es mit sich, dass weder es selbst noch die darauf platzierten Steuerelemente anklickbar sind und überhaupt auf keine Maus-Kommandos mehr reagieren. Der Aktiviert-Status als auch der Tastastur-Fokus bleiben allerdings davon unberührt: Das unsichtbare Form ist trotzdem aktiv und das Steuerelement, das den Fokus inne hat, reagiert ganz normal auf Tastatureingaben. Sie müssten also mindestens das Form im unsichtbaren Zustand sperren (Enabled = False), um unbeabsichtigte Tastatur-Eingaben zu unterbinden.

Wenn es, wie im eingangs angedeuteten Szenario nur um eine verzögerte Sichtbarkeit gehen sollte, würde es eigentlich genügen, die Enabled-Eigenschaft des Forms zur Entwicklungszeit auf False zu setzen, und dann während der Laufzeit nach dem sichtbar machen auf True zu setzen. Doch hier spielt uns VB wegen unserer Trickserei ein paar kleine Streiche (Rache ist ja bekanntlich süß...!): Auf dem sichtbar gewordenen Form hat kein Steuerelement den Fokus inne - auch nicht wie üblich dasjenige mit dem TabIndex 0. Und ein CommandButton, dessen Default-Eigenschaft gesetzt ist, erscheint und funktioniert nicht als Default-Schaltfläche.

Diese kleine Gemeinheit parieren Sie ganz einfach damit, dass Sie nach dem sichtbar Machen den Fokus ausdrücklich auf das Steuerelement, das den TabIndex 0 hat, setzen: Der Fokus ist wieder dort, wo er hingehört, und eine Default-Schaltfläche ist wieder ganz brav eine Default-Schaltfläche.

Damit ist es aber noch nicht genug der "Rache-Akte" seitens des VB-Managements. Denn wenn Sie etwa das modale Form mehrmals nacheinander verbergen und wieder anzeigen wollen (es etwa wie im zu diesem Artikel herunterladbaren Beispiel blinken lassen wollen), nützt beim zweiten Verbergen das bloße Sperren des Forms nichts mehr: Tastatureingaben kommen aus unerfindlichen Gründen trotzdem bei den Steuerelementen des Forms an. In diesem Fall müssen Sie beim Verbergen des Forms alle Steuerlemente einzeln sperren und beim sichtbar Machen wieder entsperren. Letzteres werden Sie natürlich nur bei den Steuerelementen tun wollen, die auch im sichtbaren Zustand des Forms nicht aus anderen Gründen gesperrt bleiben sollen. Dies verkompliziert den Code unter Umständen um einiges - aber schließlich sind Sie hier ja derjenige, der VB austricksen will und der daher die Mühen auf sich nehmen muss!

Keine Bange - Sie haben sich zu früh "gefreut". Verwenden Sie die folgenden Hilfsprozeduren (untergebracht in einem eigenen Standard-Modul), die alles und für alle Fälle für Sie erledigen.

Private Declare Function CreateRectRgn Lib "gdi32" _
 (ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, _
 ByVal Y2 As Long) As Long
Private Declare Function SetWindowRgn Lib "user32" _
 (ByVal hWnd As Long, ByVal hrgn As Long, _
 ByVal Redraw As Boolean) As Long

Public Sub FormTransparent(Form As Form, _
 Optional DoNotTouchEnabledControls As Variant)

  Dim nRgn As Long
  
  nRgn = CreateRectRgn(0, 0, 0, 0)
  SetWindowRgn Form.hWnd, nRgn, True
  zEnable False, Form, DoNotTouchEnabledControls
End Sub

Public Sub FormOpaque(Form As Form, _
 Optional DoNotTouchEnabledControls As Variant)

  Dim nControl As Control
  Dim nControls() As Control
  Dim i As Integer
  
  zEnable True, Form, DoNotTouchEnabledControls
  With Form
    SetWindowRgn .hWnd, 0, True
    ReDim nControls(0 To .Controls.Count)
    On Error Resume Next
    For Each nControl In .Controls
      Set nControls(nControl.TabIndex) = nControl
    Next
  End With
  Err.Clear
  For i = 0 To UBound(nControls)
    With nControls(i)
      .SetFocus
      If Err.Number Then
        Err.Clear
      Else
        Exit For
      End If
    End With
  Next 'i
End Sub

Private Sub zEnable(ByVal Enabled As Boolean, Form As Form, _
 Optional DoNotTouchEnabledControls As Variant)

  Dim nControl As Control
  Dim nControls As Collection
  Dim i As Integer
  Dim nControlsA() As Control
  
  Set nControls = New Collection
  If Not IsMissing(DoNotTouchEnabledControls) Then
    For i = LBound(DoNotTouchEnabledControls) To _
     UBound(DoNotTouchEnabledControls)
      nControls.Add DoNotTouchEnabledControls(i), _
       CStr(ObjPtr(DoNotTouchEnabledControls(i)))
    Next
  End If
  On Error Resume Next
  With Form
    For Each nControl In Form.Controls
      nControls.Add nControl, CStr(ObjPtr(nControl))
      If Err.Number = 0 Then
        nControl.Enabled = Enabled
      End If
      Err.Clear
    Next
    .Enabled = Enabled
  End With
End Sub

Bei den Prozeduren FormTransparent und FormOpaque können Sie optional ein Array von Steuerelementen übergeben, die von der Sperrung im unsichtbaren Zustand unberührt bleiben sollen (etwa ein zur blinkenden Anzeige benötigter Timer). Die private Hilfsprozedur zEnable übergeht die in dem Array enthaltenen Steuerelemente beim Sperren bzw. Entsperren.

Diese Steuerelemente werden dazu in eine Collection eingefügt, wobei als Schlüssel jeweils der mittels der (undokumentierten) VB-Funktion ObjPtr ermittelte und in einen String konvertierte (VB-interne) Objekt-Zeiger dient. Kann beim nachfolgenden Durchlauf durch die Controls-Collection des Forms ein Steuerelement nicht auch noch in diese Collection eingefügt werden, weil es bereits darin enthalten ist, wird es übersprungen und dessen Enabled-Eigenschaft bleibt unverändert.

Um den Fokus nach dem sichtbar Machen in der Prozedur FormOpaque auf das erste mögliche Steuerelement zu setzen (es ist ja nicht garantiert, dass das Steuerelement mit dem TabIndex 0 tatsächlich auch selbst sichtbar und entsperrt ist), werden alle Steuerelemente anhand ihres TabIndex in ein Array eingefügt (Steuerelemente ohne TabIndex-Eigenschaft werden dabei per Fehlerbehandlung mit "On Error Resume Next" einfach übersprungen). Anschließend wird in einer Schleife versucht, beginnend beim ersten Element (Index 0) des Arrays, den Fokus auf das im jeweiligen Element abgelegte Steuerelement zu setzen. Klappt das nicht, etwa weil das betreffende Steuerelement unsichtbar oder gesperrt ist, oder weil es nicht über eine Enabled-Eigenschaft verfügt, wird die Schleife weiter durchlaufen. Im Erfolgsfall wird die Schleife verlassen - und der Fokus ist gesetzt.


Beispiel-Projekt und Modul modModalHide (modalhide.zip - ca. 4,4 KB)


Artikel
Zum Download-Bereich dieses Artikel
Mail an den Autor dieses Artikels

KnowHow
Zur KnowHow-Übersicht

KnowHow-Themen
Themen - Allgemeines
Themen - Entwicklungsumgebung (VB-IDE)
Themen - Forms
Themen - Steuerelemente (Controls)
Themen - Grafik
Themen - Dateien
Themen - UserControls
Themen - Einsteiger-Tipps
Themen - Wussten Sie...?

Übersicht nach Titeln in alphabetischer Reihenfolge
Übersicht nach Erscheinungsdatum

Schnellsuche




Zum Seitenanfang

Copyright © 1999 - 2017 Harald M. Genauck, ip-pro gmbh  /  Impressum

Zum Seitenanfang

Zurück...

Zurück...

Download Internet Explorer