Fensterpositionen speichern und wiederherstellen

Datenbank

Formulare öffnet Access entweder immer zentriert oder an der im Entwurfsmodus zuletzt gewählten Position. Häufig möchten Sie die Formulare aber genauso positionieren, wie sie beim Verlassen der Datenbank angeordnet waren. Gleiches gilt für die Größe: Auch hier wäre es extrem arbeitssparend, wenn einmal eingestellte Fenstergrößen wiederhergestellt werden könnten. Wir möchten Ihnen eine Lösung vorstellen, mit der Sie eine solche Funktion universell in beliebige Datenbanken einbinden und nach geringen Anpassungen in allen Ihren Formularen verwenden können.

Am schnellsten und einfachsten könnten Sie eine solche Lösung realisieren, wenn Access-Formulare zur Positionierung die Eigenschaften „Top“ und „Left“ zur Verfügung stellen würden, aber leider gibt es sie nicht. Das Entwicklerteam von Access ist hier etwas inkonsequent gewesen. Die Position können Sie zwar setzen, aber nirgendwo auslesen. Die einzige Alternative dazu ist der Einsatz von API-Funktionen. Unsere Lösung ist so aufgebaut, dass ein Formular jedes Mal beim Entladen eine Prozedur aufruft, die seine aktuelle Position und Größe speichert. Beim Laden des Formulars erfolgt der Aufruf einer zweiten Prozedur, die die zuvor gespeicherten Werte ausliest, das Formular an die entsprechende Position verschiebt und die zuletzt eingestellte Größe setzt.

Für die Speicherung verwenden wir die Registry, da sie zentral aus allen Datenbanken heraus erreichbar ist und Access mit „SaveSetting“ und „GetSetting“ einfach zu handhabende Anweisungen für den Zugriff zur Verfügung stellt. Als Kriterium für das Speichern der Werte kommt eine Kombination aus Datenbankund Formularnamen zum Einsatz, sodass auch Formulare korrekt behandelt werden, die zwar den gleichen Namen haben, aber in verschiedenen Datenbanken gespeichert sind.

Wir haben für Sie eine Beispieldatenbank vorbereitet, in der Sie unsere Technik sofort einmal ausprobieren können. Starten Sie die Datenbank.

Unser Beispiel enthält die Formulare „Test 1“, „Test 2“ und „Test 3“, die Sie einfach einmal öffnen, verschieben, schließen und dann erneut öffnen sollten. Sie werden feststellen, dass jedes Formular beim erneuten Öffnen wieder exakt an der Position erscheint, an die Sie es zuletzt verschoben hatten. Die Formulare „Test 1“ und „Test 2“ sind übrigens auf feste Fenstergrößen eingestellt, das Speichern/ Setzen geänderter Größen können Sie mit dem Formular „Test 3“ testen.

So statten Sie Ihre Formulare mit der neuen Funktion aus

Alle notwendigen Deklarationen und Funktionen haben wir in dem Modul „modFormPos“ zusammengefasst, das zunächst aus unserer Beispieldatei in die Datenbank übertragen werden muss, in der Sie die Lösung einsetzen möchten. Danach können Sie die Prozeduren „FormPosSave“ und „FormPosSet“, wie im Folgenden erläutert, einsetzen.

Die Anbindung der beiden Prozeduren erfolgt über die Ereignisprozeduren „Beim Entladen“ und „Beim Laden“ eines Formulars. Die Aufrufe dieser beiden Prozeduren müssen also in die entsprechenden Ereignisprozeduren für alle Formulare aufgenommen werden, deren Positionen und/oder Größen gespeichert und gesetzt werden sollen:

  1. Öffnen Sie das Formular, in dem die Lösung eingesetzt werden soll, im Entwurfsmodus.
  2. Wählen Sie das Menü ANSICHT-EIGENSCHAFTEN an.
  3. Stellen Sie die Eigenschaft „Beim Laden“ auf den Eintrag „[Ereignisprozedur]“ ein und klicken Sie auf die Schaltfläche mit den drei Punkten, um den VBA-Editor zu öffnen. Hier geben Sie die folgende Anweisung ein:

    Sub Form_Load()
    FormPosSet Me
    End Sub

    Diese Anweisung sorgt nun dafür, dass beim Öffnen/Laden eines Formulars dessen zuvor gespeicherte Position/ Größe gesetzt wird. Verlassen Sie dann den VBA-Editor wieder.

  4. Stellen Sie die Eigenschaft „Beim Entladen“ auf den Eintrag „[Ereignisprozedur]“ und klicken Sie auf die Schaltfläche mit den drei Punkten. Geben Sie dann die folgende Anweisung ein:

    Sub Form_Load()
    FormPosSave Me
    End Sub

Diese Anweisung sorgt dafür, dass Position und Größe des Formulars bei jedem Schließen/Entladen gespeichert werden. Verlassen Sie dann wieder den VBA-Editor.

  • Wiederholen Sie Schritt 1 bis 4 für alle Formulare, deren Positionen/ Größen gespeichert/gesetzt werden sollen.Wenn die beiden Ereignisprozeduren mit den notwendigen Anweisungen versehen sind, ist die Lösung sofort einsatzbereit.

 

Mit diesen API-Funktionen wird die Anwendung erst möglich

Das Windows-API stellt die Funktionen „GetWindowRect()“ und „MoveWindow()“ zur Verfügung, über die sich die aktuelle Position und Größe eines Fensters auslesen beziehungsweise setzen lassen. Mithilfe von „GetWindowRect()“ sind wir also in der Lage, beim Schließen eines Formulars Position und Größe zu ermitteln. Beim Laden eines Formulars übergeben wir die gespeicherten Daten dann an „MoveWindow()“, um das Formular an die ursprüngliche Position in der derzeit eingestellten Größe zu setzen.

Die Methode „DoCmd.MoveSize“ kann übrigens nicht verwendet werden, da sie mit der Maßeinheit „Twips“ arbeitet, die Daten aber hier in der Maßeinheit „Pixel“ vorliegen.

Für die Speicherung verwenden wir, wie eingangs erwähnt, die Registry und darin den für Office-Anwendungen vorgesehenen Bereich „VB and VBA Program Settings“. Dort legen wir einen Abschnitt „FormPos“ an, der pro Datenbank weitere Abschnitte unter deren Namen beinhaltet, in denen dann Positionen und Größen unter den Namen der einzelnen Formulare gespeichert sind. Alle notwendigen Anweisungen und die Aufrufe der API-Funktionen haben wir in zwei Prozeduren, „FormPosSave“ und „FormPosSet“, zusammengefasst. Das Speichern der aktuellen Positionen/Größen sieht folgendermaßen aus:

Sub FormPosSave(F As Form)
Dim rectForm As tRECT
Dim rectParent As tRECT
Dim strDBName As String, strSection As String
Dim hWndParent As Long
Dim R As Variant

‚Datenbank-Name ermitteln
strDBName = CurrentDb.Name ‚Laufwerk:\Pfad\Dateiname.Erw
strDBName = NameOnly(strDBName) ‚Laufwerk/Pfad und Erweiterung raus…

strSection = strDBName & „\“ & F.Name

Hier ermitteln wir zunächst über die Eigenschaft „Name“ den Namen der aktuellen Datenbank, die über CurrentDb“ referenziert wird. Dieser Name beinhaltet Laufwerk, Pfad und Erweiterung, die wir allerdings nicht benötigen und über die Funktion „NameOnly()“ herausfiltern.

Übrig bleibt der reine Name der Datenbank. Daraus und aus dem Namen des Formulars setzen wir den Namen des Registry-Abschnitts zusammen, unter dem die Werte gespeichert werden sollen.

‚Handle des Access-Fensters ermitteln
‚hWndParent = Application.hWndAccessApp
hWndParent = GetParent(F.Hwnd)

Anschließend ermitteln wir das Window- Handle des dem Formular übergeordneten Fensters, also des Access-Anwendungsfensters, da wir Positionen/Größen bezogen auf dieses Fenster und nicht bezogen auf den Bildschirm benötigen.

Aus unerfindlichen Gründen kann „Application. hWndAccessApp“ nicht verwendet werden. Das Handle zeigt vermutlich auf den Innenbereich des Access-Fensters ohne Titelleiste, Menüs und Symbolleisten, sodass eine spätere falsche Positionierung die Folge wäre. Hier hilft uns die API-Funktion „GetParent()“, die für das Formular das richtige Handle auf das übergeordnete Fenster meldet.

‚Koordinaten des Formulars bestimmen
R = GetWindowRect(F.Hwnd, rectForm)
If Not R Then
MsgBox „Fehler beim Auslesen der Fensterposition…“, vbCritical, „FormPosSave“
Exit Sub ‚Keine weiteren Aktionen…
End If

In diesen Bereichen lesen wir die Positionen/Größen des Formulars und des Access- Fensters aus, speichern diese in speziellen Datenstrukturen …

‚Werte in Registry speichern
strSection = strDBName & „\“ & F.Name
SaveSetting „FormPos“, strSection, „X1“, rectForm.lngX1 – rectParent.lngX1
SaveSetting „FormPos“, strSection, „Y1“, rectForm.lngY1 – rectParent.lngY1
SaveSetting „FormPos“, strSection, „X2“, rectForm.lngX2 – rectParent.lngX1
SaveSetting „FormPos“, strSection, „Y2“, rectForm.lngY2 – rectParent.lngY1

End Sub

… und schreiben die Ergebnisse dann in die Registry, wobei die absolute Positionierung im Access-Fenster berücksichtigt wird.

Das Auslesen und Setzen der gespeicherten Werte übernimmt die folgende Prozedur:

Sub FormPosSet(F As Form)
Dim rectForm As tRECT
Dim strDBName As String, strSection As String
Dim lngBreite As Integer
Dim lngHoehe As Integer
Dim R As Variant

‚Datenbank-Name ermitteln
strDBName = CurrentDb.Name ‚Laufwerk:\Pfad\Dateiname.Erw
strDBName = NameOnly(strDBName) ‚Laufwerk/Pfad und Erweiterung raus…

‚Position/Größe aus Registry lesen
strSection = strDBName & „\“ & F.Name

Hier ermitteln wir zunächst wieder über die Eigenschaft „Name“ den Namen der aktuellen Datenbank, filtern über die Hilfsfunktion „NameOnly()“ Laufwerk, Pfad und Erweiterung heraus und setzen den Abschnittsnamen für die Speicherung in der Registry zusammen.

‚Position/Größe aus Registry lesen
strSection = strDBName & „\“ & F.Name
With rectForm
.lngX1 = Val(GetSetting(„FormPos“, strSection, „X1“, „0“))
If .lngX1 = 0 Then Exit Sub ‚Keine/Ungültige Settings…
.lngY1 = Val(GetSetting(„FormPos“, strSection, „Y1“, „0“))
If .lngY1 = 0 Then Exit Sub ‚Keine/Ungültige Settings…
.lngX2 = Val(GetSetting(„FormPos“, strSection, „X2“, „0“))
If .lngX2 = 0 Then Exit Sub ‚Keine/Ungültige Settings…
.lngY2 = Val(GetSetting(„FormPos“, strSection, „Y2“, „0“))
If .lngY2 = 0 Then Exit Sub ‚Keine/Ungültige Settings…
lngBreite = .lngX2 – .lngX1
lngHoehe = .lngY2 – .lngY1
‚und setzen…
R = MoveWindow(F.Hwnd, .lngX1, .lngY1, lngBreite, lngHoehe, 1)
End With

End Sub

Die aus der Registry gelesenen Werte übertragen wir dann in eine Datenstruktur, die der API-Funktion „MoveWindow()“ als Parameter übergeben wird. Sie beinhaltet die X/Y-Koordinaten (top/left, linke obere Ecke) sowie Angaben zur Breite/Höhe, die für das jeweilige Fenster gesetzt werden sollen.


Modul: modFormPos