Access-FAQ: Rund um Formulare

Karl Donaubauer, Wien

In der Access-FAQ von Karl Donaubauer (www.donkarl.com) finden Sie die meistgestellten Fragen und Anworten zum Thema Microsoft Access. In dieser Beitragsreihe stellt Karl Donaubauer die wichtigsten Einträge im Detail vor und zeigt Ihnen entsprechende Lösungen anhand praxisnaher Beispiele. Im siebten Teil lernen Sie die Lösungen zu den meistgenannten Problemen der Teilnehmer der deutschsprachigen Access-Newsgroups im Zusammenhang mit Formularen und Unterformularen kennen.

In vielen Situationen ist es notwendig zu wissen, ob ein bestimmtes Formular geöffnet ist, zum Beispiel damit ein Requery-Befehl oder ein anderer Bezug auf das Formular nicht zu einem Fehler führen kann. Es gibt etliche Methoden, um den Zustand eines Formulars zu prüfen. Eine ist das Durchlaufen der Forms-Auflistung, in der ja immer nur alle aktuell geöffneten Formulare stehen:

Dim frm As Form
For Each frm In Application.Forms
    If frm.Name = "FormularName" Then
        ''Aktionen durchführen
    End If
Next frm

Der einzige kleine Nachteil dieser Methode, die in allen Access-Versionen funktioniert, ist eine in der Praxis kaum jemals merkbare Verzögerung, weil alle geöffneten Formulare durchlaufen werden müssen.

Eine andere Variante ist die Verwendung der Funktion SysCmd, die bis Access 2.0 noch undokumentiert war und seit Access 95 offiziell zur Verfügung steht. Am besten verwenden Sie dazu die folgende kleine Funktion in einem Standardmodul:

Public Function fctIsFormOpen( _    StrFrmName As String) As Boolean
    fctIsFormOpen =        (SysCmd(acSysCmdGetObjectState, _        acForm, StrFrmName) > 0)
End Function

Hinweis

Auf der Begleit-CD finden Sie Beispiel-Datenbanken im Format von Access 97 und Access 2000 mit den Quellcodes und Beispielen aus diesem Artikel.

Die Funktion liefert True oder False zurück, je nachdem, ob das Formular geöffnet ist oder nicht. Der typische Aufruf dieser Funktion sieht dann so aus:

If fctIsFormOpen("NameDesFormulares") Then ...

Ab Access 2000 hat Microsoft endlich eine Möglichkeit zur Prüfung in die Access-Bibliothek eingebaut. Es handelt sich um die Eigenschaft IsLoaded. Damit können Sie für alle Access-Objekte, also auch für Tabellen, Abfragen und so weiter, prüfen, ob sie aktuell geöffnet sind. Für ein Formular sieht das so aus (in einer Zeile):

Abb. 1: Zwei Instanzen desselben Formulars

Dim myCopy As Form
Private Sub btnNeueInstanz_Click()
    Dim rs As DAO.Recordset
    Set myCopy = New Form_frmInstanzen
    Set rs = myCopy.RecordsetClone
    With myCopy
        .Visible = True
        .Caption = .Caption & " - Kopie"
        DoCmd.MoveSize 2000, 2000
        If Not IsNull(Me!cboAuswahl) Then
            rs.FindFirst "ArtikelId = " & Me!cboAuswahl
            If Not rs.NoMatch Then
              .Bookmark = rs.Bookmark
            End If
        End If
    End With
    Set rs = Nothing
End Sub

Quellcode 1

CurrentProject.AllForms("FormularName").IsLoaded

Im Gegensatz zur oben angeführten Prüfung mit der selbst erstellten Funktion liefert die Eigenschaft IsLoaded drei mögliche Ergebnisse. True, wenn das Objekt geöffnet ist, False, wenn es nicht geöffnet ist, und als dritte Variante den Laufzeitfehler 2467, wenn ein nicht vorhandener Objektname verwendet wurde. Den Fehler können Sie natürlich abfangen, aber das bedeutet immerhin etwas Mehrarbeit.

Ab der Version 95 bietet Access die Möglichkeit, mehrere Instanzen desselben Formulars zu öffnen. Das typische Anwendungsbeispiel ist das Anzeigen mehrerer Datensätze neben- oder übereinander (s. Abb. 1).

In der Beispiel-Datenbank zu diesem Artikel finden Sie das Formular frmInstanzen, das den nötigen Code und die praktische Anwendung demonstriert (s. Quellcode 1).

Im Kombinationsfeld des Beispielformulars können Sie einen anderen Artikel auswählen, der dann beim Klicken der Befehlsschaltfläche in einer neuen Formularinstanz angezeigt wird.

Von „Instanzen“ spricht man in diesem Zusammenhang schon deshalb, weil es sich um eine neue Instanz der Klasse des Formulars handelt. Das ist eine der vielen Gelegenheiten, bei denen man Access beziehungsweise VBA die Objektorientierung ansieht.

Die wesentlichen Teile des Codes sind dementsprechend objektorientiert. Zuerst erfolgt die Deklaration eines Formular-Objekts im Deklarationsbereich des Formular-Klassenmoduls mit

Declare Function GetSystemMetrics Lib "user32" (ByVal nIndex As Long) As Long
Const SM_CXSCREEN = 0
Const SM_CYSCREEN = 1
Public Function fctAufloesung()
    fctAufloesung = "Pixel horizontal: " & GetSystemMetrics(SM_CXSCREEN) _
        & "  vertikal: " & GetSystemMetrics(SM_CYSCREEN)
End Function

Quellcode 2

Dim myCopy As Form

Hier könnte man auch den Namen des speziellen Formulars verwenden, also

Dim myCopy As Form_frmInstanzen

Im Ereigniscode Beim Klicken der Schaltfläche wird dann die Klasse instanziiert mit

Set myCopy = New Form_frmInstanzen

Die neue Formularinstanz ist vorläufig noch nicht sichtbar. Das geschieht erst mit der Codezeile

.Visible = True

Der restliche Code sorgt dafür, dass die neue Instanz nicht genau über der ersten geöffnet wird und dass ein anderer Datensatz angezeigt wird, sofern im Kombinationsfeld einer ausgewählt wurde.

Wenn Sie in der neuen Instanz wieder auf die Schaltfläche klicken, wird die nächste Instanz erzeugt. Sie liegt jedoch genau über der aufrufenden. Deshalb müssen Sie das Fenster etwas verschieben, um den neuesten Klon zu sehen.

Eine alte Schwäche von Access ist, dass sich seine Formulare nicht von selbst dynamisch an die Größe des Bildschirmes anpassen. Die meisten Entwickler gehen daher den Weg, eine Standardauflösung für ihre Anwendung vorzusehen, beziehungsweise beim Anwender vorzuschreiben. Dennoch geschieht es in der Praxis oft, dass ein Anwender mit einer anderen Auflösung arbeitet und dann die Formulare entweder zu groß oder zu klein erscheinen.

Möchten Sie Ihre Anwendung an verschiedene Auflösungen anpassen, so ist der erste Schritt das Ermitteln der aktuellen Bildschirmauflösung. Mithilfe der API-Funktion GetSystemMetrics ist das keine große Sache (s. Quellcode 2).

Die kleine Beispielfunktion fctAufloesung in Quellcode 2 zeigt auch gleich beispielhaft den Aufruf der API-Funktion. GetSystemMetrics(SM_CXSCREEN) liefert die Breite des Bildschirmes in Pixeln, GetSystemMetrics(SM_CYSCREEN) liefert die Höhe.

Der schwierigere Teil der Arbeit ist die Größenanpassung der Formulare. Falls sie eine unbedingte Vorgabe ist und Sie nicht viel Zeit oder Mühe investieren möchten, gibt es einen einfachen Workaround, um zumindest zwei oder drei Standardauflösungen zu bedienen: Fertigen Sie für jede zu unterstützende Auflösung eine angepasste Kopie der Formulare an.

Ermitteln Sie beim Programmstart die Werte für die Breite und Höhe des Bildschirms und schreiben Sie sie in eine Variable. In der Anwendung rufen Sie dann die jeweils passende Kopie der Formulare auf. Ein Nachteil dieser Methode ist natürlich, dass bei Entwurfsänderungen auch die Kopien gepflegt werden müssen.

Type Rect
    x1 As Long
    y1 As Long
    x2 As Long
    y2 As Long
End Type
Declare Function GetWindowRect Lib "user32" (ByVal hWnd As Long, lpRect As Rect) _    As Long
Declare Function IsZoomed Lib "user32" (ByVal hWnd As Long) As Long
Declare Function ShowWindow Lib "user32" (ByVal hWnd As Long, _    ByVal nCmdShow As Long) As Long
Declare Function MoveWindow Lib "user32" (ByVal hWnd As Long, ByVal X As Long, _    ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, _    ByVal bRepaint As Long) As Long
Declare Function GetParent Lib "user32" (ByVal hWnd As Long) As Long
Declare Function GetClientRect Lib "user32" (ByVal hWnd As Long, _    lpRect As Rect) As Long
Public Const SW_MAXIMIZE = 3
Public Const SW_SHOWNORMAL = 1
Sub MaximizeRestoredForm(F As Form)
    Dim MDIRect As Rect
    If IsZoomed(F.hWnd) <> 0 Then
        ShowWindow F.hWnd, SW_SHOWNORMAL
    End If
    GetClientRect GetParent(F.hWnd), MDIRect
    MoveWindow F.hWnd, 0, 0, MDIRect.x2 - MDIRect.x1, MDIRect.y2 - MDIRect.y1, True
End Sub

Quellcode 3

Die wirklich dynamische Anpassung der Formulare an die Bildschirmauflösung ist hingegen ein technisch sehr aufwändiges Unterfangen und erfordert viel Programmcode. Es müssen ja alle Steuerelemente, Beschriftungen, Schriftgrößen, grafischen Elemente und so weiter an die jeweilige Auflösung angepasst werden.

Der Code hierfür würde den Rahmen dieses Artikels sprengen. Es gibt entsprechenden Code in Büchern und auf Webseiten, sowohl gratis als auch käuflich, die sich über eine Websuche finden lassen. Sogar bei kommerziellen Tools kommt es aber in manchen Details bei den Proportionen oder Schriftgrößen zu Problemen.

Der Code, um ein Formular zu maximieren, wiederherzustellen oder zu minimieren ist einfach und weithin bekannt:

DoCmd.Maximize
DoCmd.Restore
DoCmd.Minimize

Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
Hier geht es zur Bestellung des Jahresabonnements des Magazins Access im Unternehmen:
Zur Bestellung ...
Danach greifen Sie sofort auf alle rund 1.000 Artikel unseres Angebots zu - auch auf diesen hier!
Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar