Welcher Message Handler für DoModal() nachdem Dialog vollständig angezeigt ?
-
Hallo,
ich erzeuge einen Dialog mit DoModal(). Nun suche ich eine Funktion, die aufgerufen wird nachdem der Dialog komplett angezeigt wird.
OnCreate(), OnInitDialog() und OnShowWindow() werden alle durchlaufen bevor der Dialog sichtbar ist. Gibt es nicht eine Funktion, die danach aufgerufen wird?
Grüße
-
WM_WINDOWPOSCHANGED, aber die Antwort ist komplizierter.
Es gibt eine bekannte gute Abhandlung dazu hier:
http://blogs.msdn.com/oldnewthing/archive/2006/09/25/770536.aspxSehr lesenswert!
-
Danke für deine Antwort Martin,
ich habe es nun allerdings bereits mit einem Timer gelöst, das erspart mit auch das Auslagern des Codes vom Hauptdialog in den modalen Dialog. Den Artikel werde ich mir bei Gelegenheit mal genauer durchlesen.
Ich habe aber schon wieder ein neues Problem mit dem modalen Dialog.
Und zwar kopiere ich Dateien, der modale Dialog soll den Fortschritt mit einem Progress Bar Control anzeigen. Das Ganze läuft dann folgendermaßen:
-im Hauptdialog starte ich den modalen Dialog mit DoModal()
-in seiner OnInitDialog() rufe ich eine Methode des Hauptdialogs auf, welche den Timer mit SetTimer() startet
-die OnTimer() führt den Kopiervorgang durch und aktualisiert die Progress Bar.
Dann beendet sie den modalen Dialog über eine seiner Methoden, die OnOK() aufruft. Am Ende stoppt sie den Timer mit KillTimer().Jetzt läuft die Methode des Hauptdialogs weiter und verwendet den modalen Dialog noch ein zweites Mal. Bei dem zweiten Mal wird der Dialog allerdings nur manchmal angezeigt, manchmal ist er aber nicht sichtbar. Vorhanden ist er allerdings, was ich durch traces überprüft habe. Das erste Mal wird er immer angezeigt.
Eine zweite Instanz des Dialogs-Objekts hat auch nichts gebracht, auch nicht das Ersetzen von OnOK() durch:
EndModalLoop(0);
CWnd::OnClose();Wie beende ich denn den modalen Dialog richtig, sodass ich ihn auch ein zweites Mal anzeigen kann? Oder was mache ich sonst falsch?
-
Modale Dialoge werden nur durch EndDialog beendet!
Alles andere ist falsch.
-
Du hast recht, allerdings wird CDialog::OnOK() auch nichts anderes aufrufen als EndDialog(IDOK).
Ich bin der Lösung des unsichtbaren Dialogs gerade auf der Spur. Ich vermute, der zweite Dialog wird bereits aufgerufen bevor der erste vollständig zerstört ist.
In der MSDN zu EndDialog():
http://msdn2.microsoft.com/en-us/library/ms645472.aspx
steht folgendes:EndDialog does not destroy the dialog box immediately. Instead, it sets a flag and allows the dialog box procedure to return control to the system. The system checks the flag before attempting to retrieve the next message from the application queue. If the flag is set, the system ends the message loop, destroys the dialog box, and uses the value in nResult as the return value from the function that created the dialog box.
Wenn ich ein Sleep reinmache nachdem ich den ersten Dialog beendet habe funktioniert es.
Allerdings möchte ich ein Sleep lieber vermeiden.
Wie kann ich denn abfragen, ob ein Dialog vollständig zerstört ist?
-
Ok, also die Lösung mit dem Timer bringt mir nur weitere Probleme ein. Mein erster Ansatz war doch der richtige.
Ich habe mir den Link jetzt mal durchgelesen und möchte das auch so lösen wie dort beschrieben, allerdings ist das alles Win-API.
Ich müsste die Nachrichten WM_INITDIALOG, WM_CLOSE, WM_WINDOWPOSCHANGED und WM_APP abfangen. Für die ersten drei kann ich in MFC ja OnInitDialog(), OnClose() und OnWindowPosChanged() verwenden, bzw. um die ersten beiden muss ich mich gar nicht kümmern, so wie ich das verstehe.
Doch wie fange ich die WM_APP ab, bzw. mit welcher Methode?
Ich wäre echt dankbar, wenn mir jemand helfen könnte.
-
WM_APP ist keine Nachricht, die das System von sich aus versendet - das ist der Startpunkt des Bereiches, wo du deine eigenen Nachrichten definieren (und per SendMessage()/PostMessage() versenden) kannst. Wenn du dort nichts definiert hast, brauchst du dich nicht darum zu kümmern, andernfalls kannst du dir eine eigene Behandlungsmethode schreiben und von Hand in die Message-Map eintragen.
-
Ich habe jetzt die letzte Lösung aus dem Artikel von
http://blogs.msdn.com/oldnewthing/archive/2006/09/25/770536.aspxin MFC umgebaut, mein Code sieht folgendermaßen aus:
BEGIN_MESSAGE_MAP(ProgressDlg, CDialog) ON_WM_WINDOWPOSCHANGED() ON_COMMAND(WM_APP, OnApp) END_MESSAGE_MAP() BOOL ProgressDlg::OnInitDialog() { CDialog::OnInitDialog(); dlgShown = false; return TRUE; // return TRUE unless you set the focus to a control } void ProgressDlg::OnWindowPosChanged(WINDOWPOS* lpwndpos) { if((lpwndpos->flags & SWP_SHOWWINDOW) && !dlgShown) { dlgShown = true; PostMessage(WM_APP); } } void ProgressDlg::OnApp() { MessageBox( IsWindowVisible() ? TEXT("Visible") : TEXT("Not Visible"), TEXT("Title"), MB_OK); }
Das Programm führt die PostMessage() zwar aus, springt aber nie in die OnApp().
Was mache ich denn noch falsch?
-
Hat mir denn niemand ne Idee?
Mit dem Code möchte ich folgendes erreichen:
When we learn that the dialog is being shown for the first time, we post a message to ourselves to display the secondary dialog and return from the WM_WINDOWPOSCHANGED handler. This allows the window positioning operation to complete. Everybody gets their notifications, they are all on board with the state of the windows, and only after everything has stabilized do we display our message box.
Ich habe noch nicht so viel Ahnung von Messages. Alles was ich ja eigentlich nur machen will steht in meinem ersten Post.
Muss ich denn statt diesem ON_COMMAND(WM_APP, OnApp) irgendeine andere Methode verwenden, PreTranslateMessage() oder so was (keine Ahnung davon). Oder muss ich statt WM_APP was anderes verschicken (und was?). Die MFC-Tutorials, die ich so kenne, erzählen dazu nur Zeugs, dass ich schon kenne, nicht nützliches.
-
ich würde es mal mit ON_MESSAGE(WM_APP, OnApp) versuchen könnte mehr helfen.
Gruß Matthias
-
Jetzt funktionierts!
Vielen Dank für deine Hilfe, auch den anderen beiden
Ich habe noch die folgenden drei Zeilen abgeändert:
ON_MESSAGE(WM_APP, OnApp) LRESULT ProgressDlg::OnApp(WPARAM wParam, LPARAM lParam) { ... return 1; }
Viele Grüße