Forum: PC-Programmierung MFC-Anwendungen: Nachrichten zwischen Dialogen


von Nils (Gast)


Lesenswert?

Hallo,

ich habe eine Frage zu Nachrichten zwischen Dialogen in MFC-Anwendungen 
(MS VC++ 6).

Wenn ich von einem Dialog aus einen Handler in einem anderen Dialog oder 
dem Hauptfenster aufrufen möchte (oder Daten übergeben), mache ich 
bisher folgendes:

In der Klasse CMainFrame (MainFrm.cpp) implementiere ich für jede 
Nachricht einen Messagehandler, beispielsweise so:
ON_MESSAGE(WM_CLOSEPROJDLG, OnForwardMsg_ProjDlgCl)

In CMainFrame schreibe ich dann eine Umleitung, Beispiel:

void CMainFrame::OnForwardMsg_ProjDlgCl(){
  {Der_Empfaenger}.SendMessage(WM_CLOSEPROJDLG);
  CWnd *pwnd = GetWindow(GW_CHILD);
  pwnd -> SendMessage(WM_CLOSEPROJDLG);
}

In diesem Beispiel ist {Der_Empfaenger} meine Zielklasse.

Die Umleitung spreche ich aus dem Dialog an, beispielsweise so:
CWnd* pwnd = GetWindow(GW_OWNER);
pwnd -> SendMessage(WM_CLOSEPROJDLG);

Dieses Hin- und hergerufe kommt mir sehr umständlich vor, so dass ich 
denke dass ich ungeschickterweise Konzepte aus anderen Sprachen schlecht 
in VC++ 6 übertragen habe.

Meine Frage: Gibt es eine bessere/elegantere Methode?

Gruß & danke,
Nils

von Karl H. (kbuchegg)


Lesenswert?

Du musst dich der Grundsatzfrage stellen:
Will ich über Messages gehen bzw. was verspreche ich mir von den 
Messages?

Wenn dir dafür kein wirklich vernünftiger Grund einfällt, dann musst du 
nicht über Messages laufen, sondern kannst das alles auch mit normalen 
Funktionsaufrufen machen.
Der Mainframe muss ja auch so alle Dialoge kennen (sind offenbar nicht 
modale Dialoge) um die Message weiterrouten zu können. Ob der Mainframe 
dem jetzt eine Message schickt, oder ob der Dialog eine ganz spezielle 
Funktion dafür zur Verfügung stellt, ist gehupft wie gesprungen.
Auf der anderen Seite ist es in einem MFC Programm von überall leicht , 
an den Mainframe rannzukommen, so dass ein direkter Aufruf der 
Verteilfunktion in CMainFrame nichts im Wege steht.

Wenn es dir aber tatsächlich wichtig ist, die einzelnen Klassen 
vollständig voneinander zu entkoppeln, dann ist dein Message-Ansatz 
schon ok.

von Nils (Gast)


Lesenswert?

Hallo Karl Heinz,

danke für die ausführliche Antwort.

> ... (sind offenbar nicht modale Dialoge) ...
Doch, auch für modale Dialoge wähle ich diesen Weg. Ergeben sich da aus 
Deiner Sicht Schwierigkeiten?

> Wenn es dir aber tatsächlich wichtig ist, die einzelnen Klassen
> vollständig voneinander zu entkoppeln, dann ist dein Message-Ansatz
> schon ok.
Ja, das versuche ich tatsächlich durchzuhalten.
Aber wie ist das mit den Dialoginstanzen, die Mainframe bekannt sind? 
Wie kann ich Dialoginstanzen dieses Wissen bekannt geben, wenn ich eine 
bestimmte Methode in einem bestimmten Dialog ansprechen möchte?
Sollte ich dann die entsprechende Dialoginstanz globalisieren und das 
den miteinander kommunizierenden Dialogen per 'extern' bekannt geben? 
Das erschien mir ein bisschen windig - ich denke ich habe hier irgendwie 
Scheuklappen vor den Augen und sehe die simple Lösung nicht.

Danke schon mal für die Info, dass mein bisheriger Lösungsansatz adäquat 
ist - das beruhigt mich etwas.

Gruß,
Nils

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Warum müssen Dialoge miteinander kommunizieren? Mit dem 
"model-view-controller"- oder "Document-View"-Konzept hat das nicht viel 
zu tun.

von Nils (Gast)


Lesenswert?

Hallo Rufus,

> Warum müssen Dialoge miteinander kommunizieren?
Mal ein konkretes Beispiel:
In einem modalen Dialog habe ich eine Eingabemaske. Beim Schließen des 
Dialogs soll der Wert in der Eingabemaske einen Handler im Hauptfenster 
aufrufen, beispielsweise, um eine ComboBox um diesen Wert zu erweitern.

Wie kann man das ohne Nachrichten lösen?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Der Dialog ist modal, also gibt es eine Stelle, an der er aufgerufen 
wurde. Das wird irgendwo in einem Ereignishandler eines Views oder eines 
Frame Window geschehen.

An eben dieser Stelle kann der Rückgabewert von CDialog::DoModal() 
untersucht werden. Z.B. bei IDOK werden dann die im Dialog manipulierten 
Dinge ausgewertet und dann kann der View oder wer auch immer etwas damit 
anfangen.

von Karl H. (kbuchegg)


Lesenswert?

Rufus t. Firefly schrieb:

> An eben dieser Stelle kann der Rückgabewert von CDialog::DoModal()
> untersucht werden. Z.B. bei IDOK werden dann die im Dialog manipulierten
> Dinge ausgewertet und dann kann der View oder wer auch immer etwas damit
> anfangen.

Oder um das einmal etwas allgemeiner zu formulieren.
Ein modaler Dialog ist selten in der Verlegenheit, dass andere 
Programmteile sofort von seinen Änderungen in Kentnis gesetzt werden 
müssen (Ausnahme: Man baut einen Apply-Button ein. Daher sieht man den 
auch eher selten :-)

Die übliche Vorgehensweise ist:
Der Dialog geht davon aus, dass seine Vorgabe-Werte beim Betreten der 
OnInitDialog richtig eingestellt wurden. Zuständig dafür ist derjenige, 
der den Dialog erzeugt und das DoModal() aufgerufen hat. Seine Aufgabe 
ist es, den Dialog mit den Ausgangwerten zu versorgen.

Dann macht der Dialog sein Ding
Prüft im OnOK Handler meinetwegen noch, ob irgendwelche Randbedingungen 
erfüllt sind und beendet sich

Dann kommt wieder der Aufrufer des Dialogs zum Zug.
Seine Aufgabe ist es jetzt, im OK-Fall sich vom Dialog die Werte 
abzuholen und weiter zu verteilen / weiter zu verarbeiten.

Was ein Dialog nicht tun sollte: Direkt auf der Datenstruktur des 
Dokuments arbeiten. Das macht die Behandlung des Cancel Buttons 
schwierig. Auch ist es dann oft sehr schwer sicherzustellen, dass die 
vom Benutzer veränderten Daten in sich konsistent sind, wenn im Dialog 
bei jeder Änderung gleich die Dokument-Datenstruktur verändert wird.
Was ein Dialog auch nicht tun sollte: Sich die Daten selbst 
zusammensuchen. Es ist der Programmteil, der den Dialog öffnet, der 
dafür zuständig ist.
Aus Sicht des Dialogs sollte die Sache so sein:
 * Ich kriege Daten vorgesetzt. Und zwar in Form von Kopien. Verändere
   ich die Daten, dann passiert erst mal nichts.
 * der Benutzer bearbeitet sie
 * ich hinterlasse die Daten so, dass mein Vorgesetzter sie sich
   abholen kann. Jetzt ist es gut, dass ich immer nur auf Kopien
   gearbeitet habe, denn meinem Aufrufer steht es damit frei die
   Änderungen ganz einfach zu ignorieren (zb weil ich ihm mitteile
   dass mein Benutzer auf Cancel gedrückt hat)

Mit einem derartigen Vorgehen (und einer zentralen UpdateControls 
Funktion im Dialog, in der Dialogelemente inaktiv/aktiv gesetzt werden) 
waren zumindest bei mir die meisten Dialoge bessere Fingerübungen ohne 
gröbere Komplikationen.

Bei nicht-modalen Dialogen ist die Situation häufig unangenehmer. Aber 
die sind ja nicht betroffen.

von Nils (Gast)


Lesenswert?

Hallo Rufus, hallo Karl Heinz,

> An eben dieser Stelle kann der Rückgabewert von CDialog::DoModal()...
Das war das Wissen, das mir fehlte. (Hatte ich mir zwar schon angesehen, 
hatte aber offenbar Tomaten auf den Augen).

> Was ein Dialog nicht tun sollte: Direkt auf der Datenstruktur des
> Dokuments arbeiten.
Ja, und genau das hatte ich vor und es kam mir selber nicht ganz koscher 
vor.

Vielen dank für Eure ausführlichen Erklärungen - hat mir sehr 
weitergeholfen.

Gruß,
Nils

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.