Discussion:
Form on Unload
(zu alt für eine Antwort)
Christian Rohrbach
2003-12-14 09:29:29 UTC
Permalink
Hallo Leute,

ich schließe unter anderem ein Form von mir auf folgende Weise: DoCmd.Close
acForm, Me.Name, acSaveNo
Dieser erfolgt unter Umständen in einer SubRoutine welche von einer anderen
aufgerufen wird. Nun mußte ich leider feststellen, dass sobald die
schließende Routine verlassen wird (zurück in die aufrufende) alle Objekte
nicht mehr verfügbar sind. Da dort dann aber noch weitere Abfragen auf
Objekte stehen, gibt es einen Fehler

Kann ich irgendwie abfragen, ob sich das Formular im Zustand "Unload" bzw
Close" befindet, damit ich anhand dieser Bedingung ein Exit Sub machen kann?

Dank und Gruß, Christian
Reiner Wolff
2003-12-14 10:27:49 UTC
Permalink
Moin Christian,
DoCmd.Close acForm, Me.Name, acSaveNo
Dieser erfolgt unter Umständen in einer SubRoutine welche von einer
anderen aufgerufen wird. Nun mußte ich leider feststellen, dass
sobald die schließende Routine verlassen wird (zurück in die
aufrufende) alle Objekte nicht mehr verfügbar sind. Da dort dann aber
noch weitere Abfragen auf Objekte stehen, gibt es einen Fehler
Kann ich irgendwie abfragen, ob sich das Formular im Zustand "Unload"
bzw Close" befindet, damit ich anhand dieser Bedingung ein Exit Sub
machen kann?
Wenn ich Dich richtig verstehe, befindet sich das Formular beim
Auftauchen des Problems nicht im Zustand "Unload" oder "Close" sonders
es ist dann bereits geschlossen.
Wie Du - im nachfolgenden Code - abfragen kannst, ob ein Formular
geöffnet ist oder nicht, verrät Dir FAQ 4.19 auf www.donkarl.com

HTH
Greetinx aus Kiel
Reiner
Christian Rohrbach
2003-12-14 12:25:32 UTC
Permalink
Post by Reiner Wolff
DoCmd.Close acForm, Me.Name, acSaveNo
Dieser erfolgt unter Umständen in einer SubRoutine welche von einer
anderen aufgerufen wird. Nun mußte ich leider feststellen, dass
sobald die schließende Routine verlassen wird (zurück in die
aufrufende) alle Objekte nicht mehr verfügbar sind. Da dort dann aber
noch weitere Abfragen auf Objekte stehen, gibt es einen Fehler
Kann ich irgendwie abfragen, ob sich das Formular im Zustand "Unload"
bzw Close" befindet, damit ich anhand dieser Bedingung ein Exit Sub
machen kann?
Wenn ich Dich richtig verstehe, befindet sich das Formular beim
Auftauchen des Problems nicht im Zustand "Unload" oder "Close" sonders
es ist dann bereits geschlossen.
Wie Du - im nachfolgenden Code - abfragen kannst, ob ein Formular
geöffnet ist oder nicht, verrät Dir FAQ 4.19 auf www.donkarl.com
Stimmt, es ist bereits geschlossen, alle Objekte sind ja nicht mehr
verfügbar. Dennoch wird der Code im Formular zuende ausgeführt (es schließt
sich ja selbst mittels DoCmd.Close acForm, Me.Name, acSaveNo). (FAQ 4.19 hat
das Problem übrigens gelöst)

Kann man eigentlich das Formular per VBA schließen und die weitere
Ausführung des Quelltextes verhindern? Exit Sub schließt nur die Sub, es
wird aber, falls die Sub von irgendwo aufgerufen wurde an der Stelle
weitergemacht, auch wenn das Formular geschlossen ist (unter Access 97 war
das noch nicht so, da wurde auch der Code beendet)
Peter Doering
2003-12-14 16:06:00 UTC
Permalink
Post by Christian Rohrbach
Stimmt, es ist bereits geschlossen, alle Objekte sind ja nicht mehr
verfügbar. Dennoch wird der Code im Formular zuende ausgeführt (es schließt
sich ja selbst mittels DoCmd.Close acForm, Me.Name, acSaveNo). (FAQ 4.19 hat
das Problem übrigens gelöst)
Was hast du denn fuer Code in Form_Close oder Form_UnLoad? Vielleicht
gibt's an der Vorgehensweise was zu verbessern.
Post by Christian Rohrbach
Kann man eigentlich das Formular per VBA schließen und die weitere
Ausführung des Quelltextes verhindern? Exit Sub schließt nur die Sub, es
wird aber, falls die Sub von irgendwo aufgerufen wurde an der Stelle
weitergemacht, auch wenn das Formular geschlossen ist (unter Access 97 war
das noch nicht so, da wurde auch der Code beendet)
Nicht ganz richtig. Die aktuelle Prozedur wurde beendet, wie in allen
anderen Versionen auch. Die weitere Events treten genauso ein, es sei denn,
du cancelst ein Event durch Cancel = True (wo erlaubt) oder CancelEvent
(<F1>CancelEvent Action). Die Reihenfolge der Events findest du unter
<F1>"order of events" (sorry, hab leider keine deutsche Hilfe). Sie lautet:

(Form) Open - Load - Resize - Activate - Current - (Control) Enter -
GotFocus

und beim Schliessen:

(Control) Exit - LostFocus - (Form) Unload - Deactivate - Close.

Beispiel:
Private Sub Form_Unload(Cancel As Integer)
If MyCriteria = True Then
Cancel = True
Exit Sub
End If
End Sub

In diesem Fall werden die weiteren Events nicht getriggert.

Das aktuelle Formular kann man per

DoCmd.Close

schliessen. Die von dir verwendete Syntax benutzt man, um /andere/ als das
aktuelle Formular zu schliessen. Dann wiederum macht Me.Name keinen Sinn,
da es den Namen des aktuellen Formulars einstellt.

HTH - Peter
--
Ich beantworte keine Fragen per Email.
Mitglied im http://www.dbdev.org
FAQ: http://www.donkarl.com
Christian Rohrbach
2003-12-14 17:11:43 UTC
Permalink
Post by Peter Doering
Was hast du denn fuer Code in Form_Close oder Form_UnLoad? Vielleicht
gibt's an der Vorgehensweise was zu verbessern.
Post by Christian Rohrbach
Kann man eigentlich das Formular per VBA schließen und die weitere
Ausführung des Quelltextes verhindern? Exit Sub schließt nur die Sub, es
wird aber, falls die Sub von irgendwo aufgerufen wurde an der Stelle
weitergemacht, auch wenn das Formular geschlossen ist (unter Access 97 war
das noch nicht so, da wurde auch der Code beendet)
Nicht ganz richtig. Die aktuelle Prozedur wurde beendet, wie in allen
anderen Versionen auch. Die weitere Events treten genauso ein, es sei denn,
du cancelst ein Event durch Cancel = True (wo erlaubt) oder CancelEvent
(<F1>CancelEvent Action). Die Reihenfolge der Events findest du unter
(Form) Open - Load - Resize - Activate - Current - (Control) Enter -
GotFocus
(Control) Exit - LostFocus - (Form) Unload - Deactivate - Close.
Private Sub Form_Unload(Cancel As Integer)
If MyCriteria = True Then
Cancel = True
Exit Sub
End If
End Sub
In diesem Fall werden die weiteren Events nicht getriggert.
Das aktuelle Formular kann man per
DoCmd.Close
schliessen.
Hallo Peter,

die Eventereignisse Unload usw. machen mir keine Schwierigkeiten. Ich habe
einen Timer, der alle 10 Sekunden prüft, ob der aktuelle DS gelöscht ist.

kurze Formularbeschreibung:
es existiert auf einem Formular eine Listbox, welche beim Öffnen des
Formulars entsprechend einer Query mit Daten gefüllt wird. Der Inhalt ist
eine (gemäß Query) ausgwählte Auswahl an Primärschlüsselinhalten der dem
Formular zugrunde liegenden Tabelle. Ziel ist es bei Auswahl eines Eintrags
(der Listbox) mittels Filter den DS zu filtern, welcher dem Eintag in der
Listbox entspricht.

Erschwerende Problematik:
Es können andere User DS aus der Datenbank zwischenzeitlich löschen. Es soll
sichergestellt werden, dass niemals der Filter auf einen DS gesetzt wird,
der nicht mehr existiert. Außerdem soll die Listbox beim Feststellen einer
Manipulation der DS durch andere User aktualisiert wird (nur bei Löschungen)

etwas Pseudocode

Private Form_Timer() Aufruf erfolgt alle 10 Sekunden
'Prüfung erfolgt um zu testen, ob ein anderer User den aktuellen DS gelöscht
hat und nun in der Anzeige #gelöscht steht
wenn not isDate(Steuerelement, welches eigentlich ein Datum enthält) dann
mache ein Requery auf die Listbox
weiterer DS vorhanden?
ja: setze Filter auf den ersten DS der Listbox (ist sicher vorhanden
aufgrund des vorher stattgefundenen Requery)
nein: DoCmd.Close + Exit Sub
End sub

bis hierher kein Problem......
nun die Listbox, in welcher man durch Anklicken eines Eintrags den Filter
des Formulars neu setzt.

Listbox_after_Update()
Rufe Form_Timer (Prüfung, ob der aktuelle DS noch gültig ist)
Prüfe mittels DLookup, ob der in der Listbox ausgewählten Eintag in der DB
wirklich (noch) existiert (muß sein, könnte ja zwischenzeitlich gelöscht
sein)
ja: setze Filter auf neuen DS um (gemäß Eintag in der Listbox)
nein:
mache Requery auf Listbox (vielleicht gibt es ja noch einen....)
falls Listbox Elemente enthält: setze Filter auf den ersten
Eintag der Listbox
falls Listbox nun leer: DoCmdClose
end sub

Problematisch ist es nun, wenn die Listbox_after_Update die Form_Timer nun
aufruft und diese das Formular schließt. Denn nach dem Exit sub in
Form_Timer kommt er zur aufrufenden Prozedur zurück, in welcher dann code
steht, welcher sich auf nicht mehr existierende Steuerelemente bezieht......

Daher ist eine Abfrage hinter "Rufe Form_Timer", ob denn das Formular noch
existiert unausweichlich, ansonsten geht es auf die Bretter ((Deine Lösung
funktioniert dies bezüglich, denn Abfragen auf Steuerelemente sind nicht
mehr möglich, zumindest nicht mit isnull oder so)

Hast Du eine bessere Lösung für meinen Code?

Gruß, Christian
Peter Doering
2003-12-14 19:45:38 UTC
Permalink
Hallo Christian,
Post by Christian Rohrbach
...
etwas Pseudocode
Private Form_Timer() Aufruf erfolgt alle 10 Sekunden
'Prüfung erfolgt um zu testen, ob ein anderer User den aktuellen DS gelöscht
hat und nun in der Anzeige #gelöscht steht
wenn not isDate(Steuerelement, welches eigentlich ein Datum enthält) dann
mache ein Requery auf die Listbox
weiterer DS vorhanden?
ja: setze Filter auf den ersten DS der Listbox (ist sicher vorhanden
aufgrund des vorher stattgefundenen Requery)
nein: DoCmd.Close + Exit Sub
End sub
Wenn du das alle 10 Sek. machst, bleibt dem User nicht viel Zeit, was zu
tun, bevor's wieder flimmert.
Post by Christian Rohrbach
bis hierher kein Problem......
nun die Listbox, in welcher man durch Anklicken eines Eintrags den Filter
des Formulars neu setzt.
Listbox_after_Update()
Rufe Form_Timer (Prüfung, ob der aktuelle DS noch gültig ist)
Das solltest du unbedingt trennen:

Private Sub Form_Timer
Call DeinCheck(DeinID)
End Sub

Private Sub Listbox_After_Update
Call DeinCheck(DeinID)
End Sub

Beachte, dass in keiner der beiden Prozeduren noch Statements danach
kommen. Rest siehe unten.
Post by Christian Rohrbach
Prüfe mittels DLookup, ob der in der Listbox ausgewählten Eintag in der DB
wirklich (noch) existiert (muß sein, könnte ja zwischenzeitlich gelöscht
sein)
ja: setze Filter auf neuen DS um (gemäß Eintag in der Listbox)
mache Requery auf Listbox (vielleicht gibt es ja noch einen....)
falls Listbox Elemente enthält: setze Filter auf den ersten
Eintag der Listbox
falls Listbox nun leer: DoCmdClose
end sub
Setz das DoCmd.Close an's potentielle Ende der DeinCheck-Prozedur, dann
klappt's auch mit dem Schliessen, z.B.

Private Sub DeinCheck(ID As String)
If IsNull(DLookup(...)) Then
Me!MyListBox.Requery
End If
If Me!MyListBox.ListCount = 0 Then
DoCmd.Close 'auch hier ist Close das letzte aktive Statement
End If
End Sub
Post by Christian Rohrbach
Problematisch ist es nun, wenn die Listbox_after_Update die Form_Timer nun
aufruft und diese das Formular schließt. Denn nach dem Exit sub in
Form_Timer kommt er zur aufrufenden Prozedur zurück, in welcher dann code
steht, welcher sich auf nicht mehr existierende Steuerelemente bezieht......
Da duerfen keine mehr stehen, s.o.

HTH - Peter
--
Ich beantworte keine Fragen per Email.
Mitglied im http://www.dbdev.org
FAQ: http://www.donkarl.com
Christian Rohrbach
2003-12-14 20:19:15 UTC
Permalink
Post by Peter Doering
Post by Christian Rohrbach
Private Form_Timer() Aufruf erfolgt alle 10 Sekunden
'Prüfung erfolgt um zu testen, ob ein anderer User den aktuellen DS gelöscht
hat und nun in der Anzeige #gelöscht steht
if not isDate(Steuerelement, welches eigentlich ein Datum enthält) then
Listbox.Requery
.........
Post by Peter Doering
Post by Christian Rohrbach
End sub
Wenn du das alle 10 Sek. machst, bleibt dem User nicht viel Zeit, was zu
tun, bevor's wieder flimmert.
Private Sub Form_Timer
Call DeinCheck(DeinID)
End Sub
Private Sub Listbox_After_Update
Call DeinCheck(DeinID)
End Sub
Private Sub DeinCheck(ID As String)
If IsNull(DLookup(...)) Then
Me!MyListBox.Requery
End If
If Me!MyListBox.ListCount = 0 Then
DoCmd.Close 'auch hier ist Close das letzte aktive Statement
End If
End Sub
Du hast recht, eine Trennung ist wesentlich übersichtlicher, wollte mir ein
paar Zeilen Code sparen und habe es sogar geschafft.... (nur ist der Code
nicht mehr sonderlich leicht nachvollziehbar, insbesondere, weil so ganz
nebenbei noch ein ganzer Haufen weitere Bedingungen beachtet werden müssen
im Original).

Allerdings: Das Requery (wäre ja der Verursacher von Flimmern) wird nur
ausgeführt, wenn der DS tatsächlich gelöscht wurde (dann ist ja auch
Handlungsbedarf), ansonsten hätte ich das auch nicht eingebaut. Am besten
wäre es ja das Event (DS wurde gelöscht, in dem Moment, wenn die Anzeige auf
#gelöscht springt) zu behandelt, ich habe aber leider kein Ereignishandler
dafür gefunden... ;-(

Besten Dank fürs Mitdenken!

Gruß, Christian

Martin Peeck
2003-12-14 18:10:29 UTC
Permalink
Post by Christian Rohrbach
Hallo Leute,
ich schließe unter anderem ein Form von mir auf folgende Weise: DoCmd.Close
acForm, Me.Name, acSaveNo
Dieser erfolgt unter Umständen in einer SubRoutine welche von einer anderen
aufgerufen wird. Nun mußte ich leider feststellen, dass sobald die
schließende Routine verlassen wird (zurück in die aufrufende) alle Objekte
nicht mehr verfügbar sind. Da dort dann aber noch weitere Abfragen auf
Objekte stehen, gibt es einen Fehler
Kann ich irgendwie abfragen, ob sich das Formular im Zustand "Unload" bzw
Close" befindet, damit ich anhand dieser Bedingung ein Exit Sub machen kann?
Dank und Gruß, Christian
Hallo Christian,

du könntest die FORMS-Collection durchlaufen, um zu überprüfen, ob das
Forular noch existiert.

Mit freundlichem Gruß
Martin Peeck
________________________

Martin Peeck
Lindhöft
eMail: ***@aol.com
________________________
Loading...