2017-10-07 3 views
1

Ich muss ein Popup-Formular Größe für Benutzer, deren Bildschirm ist nicht so groß wie andere - Einstellung des Formulars auf Popup und Modal und BorderStyle Resizable hat eine große Einschränkung - den Code in Das Formular, mit dem das Popup jetzt gestartet wird, wartet nicht auf die Rückkehr des Formulars.Umgang mit einem Popup, Modal, veränderbare Form

Wie also wartet man darauf, dass ein Formular unsichtbar gemacht wird? Ich versuchte Looping mit Sleep und Doevents, aber das macht das Popup-Formular nicht sehr reaktionsschnell und zähmt CPU-Zyklen. Ich habe versucht, das form.gotfocus-Ereignis des startenden Formulars zu setzen, aber das löst nicht aus und das bedeutet, dass ich den Code teilen muss, der das Popup-Formular aus dem Code öffnete, der ausgeführt wird, nachdem das Popup-Formular geschlossen wird.

Was ist die beste Lösung?

Dank

Antwort

0

Sie das Formular mit acDialog Option öffnen:

DoCmd.OpenForm "MyFormName", WindowMode:=acDialog 

Es wird warten, bis das Formular oder versteckt geschlossen.

+0

Aber das wird die Form nicht veränderbare machen. – Andre

0

Das Problem hier ist Popup und modale Formen halten nicht aufrufenden Code.

Aber schlimmer ist Ihr Bedürfnis, Anruf-Code zu stoppen. Das erfordert ein Dialogformular.

Und schlimmer ist ein Dialogfeld Formular lässt keine Größenänderung.

Sie möchten die 3 Arten von Formularen hier nicht verwechseln.

Modale Formen - sie unterscheiden sich dann Popup-Formen und unterscheiden sich sehr von Dialogformularen.

Und das gleiche gilt für Popup-Formulare. Sie sind keine Dialogformen, und tatsächlich sind sie auch kein Modell.

Sie müssen auch berücksichtigen, wenn Sie auf Anwendung zugreifen, um Dokumente mit Registerkarten oder überlappende Fenster zu verwenden. (Dies wird Ihre Auswahl wieder begrenzen).

Wenn Sie Tabbed-Schnittstelle verwenden, dann müssen Sie ein Popup-Formular verwenden, wenn Sie re-sizable Fähigkeit wollen - aber diese Art von Formular wird nicht zum Aufrufen von Code.

Wenn Sie überlappende Fenster verwenden, empfehle ich ein modales Formular. (Aber wieder wird es den Aufruf von Code nicht stoppen, sondern wird eine erneute Größenänderung erlauben).

Während Sie "looping" Code in der aufrufenden Form annehmen können, die auf die zweite Form wartet, sind solche Schleifen Prozessorfehler und verursachen oft eine "schlechte" Reaktion in Bezug auf Maus und Typisierung.

Also würde ich vorschlagen, dass Sie Ihren Code-Ansatz ändern. Lassen Sie das aufrufende Formular das Formular als Popup starten (oder modal, wenn Sie die Tabbed-Schnittstelle nicht verwenden).

Wenn Sie dann das Formular schließen, ruft es weiteren Code auf, den Sie in dem aufrufenden Formular ausführen möchten. Das bedeutet, dass Sie den Code, den Sie nach dem Schließen des zweiten Formulars ausführen möchten, aufteilen müssen, und rufen Sie den abschließenden Formularaufruf auf und führen Sie diesen Code aus.

Ein "allgemeiner" Ansatz sollte eine harte Codierung der Formularnamen vermeiden, denn dann können "viele" Routinen und Formulare Ihre zweiten Formulare aufrufen und diese Formulare wiederverwenden.

Also das versuchen: In der zweiten Form, erstellen Sie eine Modulebene Formularvariablen wie folgt aus:

Option Compare Database 
Option Explicit 

Dim frmPrevious  As Form 

In den Formen auf offenen Veranstaltung dieser Form, greifen die Berufung Formen refeance wie folgt aus:

Set frmPrevious = screen.ActiveForm 

Jetzt in den Formen schließen Ereignis, dies tun:

frmPrevious.AfterClose

Und in der anrufenden Form, eine öffentliche Funktion

genannt erstellen

Afterclose

So in der öffentlichen Funktion in der ersten Form Sie den Code platzieren, die Sie ausführen möchten, wenn Sie das zweite Formular zu schließen. Das ist "weniger" ideal als schöner prozeduraler Code, der die 2. Form anruft, wartet und fortsetzt - aber ich denke es ist immer noch die beste Wahl.

Und bevor Sie schließen, können Sie weitergeben oder „set“ Werte an die anrufende Form zurückzukehren wie:

frmPreviuos.SomePubicVar = me!LastNameSelected 
frmPrevious!Company = me!CompanySelected 
frmPrevious.AfterClose 

In der über der ersten Zeile eine öffentliche Variable in der anrufenden Form setzt (wenn Sie möchten um dies zu tun und Werte zurück an Modulebene vars in der ersten Form zu übergeben). Und die nächste Zeile legt den Wert eines Steuerelements im aufrufenden Formular fest (wenn Sie Werte an einige Steuerelemente im aufrufenden Formular zurückgeben möchten).

Und die dritte Zeile führt den MyClose-Code im aufrufenden Formular aus. Und wenn Sie in diesem zweiten Formular eine Art "OK" oder Auswahltaste haben, dann verschieben Sie den obigen Code hinter diese Schaltfläche - da Sie nicht möchten, dass der Code ausgeführt wird, wenn das Formular eine Abbrechen-Schaltfläche hat (also würde die Abbrechen-Schaltfläche einfach) Schließen Sie das Formular - aber rufen Sie nicht + den obigen Code in der ersten Form ausführen. Und das X zu treffen würde auch als ein Abbruch oder ein Exit angesehen werden. Also würde Ihr "Speichern" oder "OK" oder "Auswählen" Knopf den obigen Code haben.

+0

Vielen Dank für die gründliche Erklärung - Sie haben eine praktikable Lösung und einige Tipps zur besseren Codierung zur Verfügung gestellt - Ich werde versuchen, eine Lösung zu finden, die die Schlafzeit verkürzt und sehen, ob das funktioniert, da der prozedurale Ansatz zu mehr sauberer Code, aber Wenn die Reaktionszeit oder CPU-Zyklus zu hoch ist, werde ich Ihre Lösung implementieren - danke – Charlie

0

Ich hatte nie Probleme mit DoEvents/Sleep 50 Schleifen. Die CPU-Belastung bleibt minimal und die Form reagiert.

Verwenden Sie mit einem sehr alten Computer möglicherweise Sleep 100.

Beispielcode:

Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) 

Sub TestOpenForm() 

    If FormOpenWait("frmPopup") Then 
     MsgBox "Form was hidden.", vbInformation 
    Else 
     MsgBox "Form was closed.", vbInformation 
    End If 

End Sub 

' Open fName, wait until it is 
' - closed : return False 
' - hidden : return True 
Public Function FormOpenWait(fName As String, Optional sOpenArgs As String = "") As Boolean 

    If IsFormLoaded(fName) Then DoCmd.Close acForm, fName, acSaveNo 

    DoCmd.OpenForm FormName:=fName, OpenArgs:=sOpenArgs 

    ' default: signal "closed" 
    FormOpenWait = False 

    ' Wait until form is closed or made invisible 
    Do While IsFormLoaded(fName) 
     If Not Forms(fName).Visible Then 
      ' Signal "hidden" 
      FormOpenWait = True 
      Exit Do 
     End If 

     ' Wait 50ms without hogging the CPU 
     DoEvents 
     Sleep 50 
    Loop 

End Function 

Public Function IsFormLoaded(fName As String) As Boolean 
    IsFormLoaded = (SysCmd(acSysCmdGetObjectState, acForm, fName) And acObjStateOpen) > 0 
End Function 
+0

Ich stimme nicht zu. Es funktioniert vollkommen in Ordnung. Den Code zu teilen ist viel hässlicher. Und wenn Sie z.B. Ich möchte warten, bis eine Abfrage (Datenblattansicht) geschlossen ist, es ist die einzige Option. @ Enigmativität – Andre

+0

Ich sehe, Sie haben ein Muster für diese. :) Aber Sie wissen, dass es sich bei dieser Frage um MS-Access und VBA handelt? Nicht C#. Es gibt keine https://stackoverflow.com/questions/5721564/multi-threading-in-vba – Andre

+0

Ah, guter Punkt. Das habe ich vermisst. Ich könnte dann diese Kommentare löschen, da sie irreführend sind. – Enigmativity