Zusammenhänge der Klassen einer SDI in der MFC



  • 1 Übersicht

    Das SDI (Single Document Interface) ist einer der Anwendungstypen, die man mit Hilfe des Assistenten erstellen kann.
    Es besteht aus mehreren Klassen, die jede ihre eigene Aufgabe haben:

    • C...App (von CWinApp abgeleitet)
      ist für globale Aufgaben zuständig,
      z.B. Datenbankinstanz bereithalten.
    • CMainFrame
      ist für die Abarbeitung und Weiterleitung von Menübefehlen zuständig.
    • C...Doc (von CDocument abgeleitet)
      ist für die Datenhaltung zuständig.
      Hier kommen z.B. die Recordsets hin.
    • C...View (von CView (oder was auch immer gewählt wurde) abgeleitet)
      ist für die Anzeige zuständig.

    Was eigentlich der Übersichtlichkeit dienen soll, macht Anfängern aber eher Probleme, denn sie finden die "Brückenschläge" zwischen den einzelnen Klassen nicht.
    Hier möchte ich Abhilfe schaffen.

    2 C...App

    An die C...App kommt man von JEDER Klasse der Anwendung aus mit

    AfxGetApp();
    

    Da das aber noch nicht den richtigen Typ hat, muss gecastet werden. Ich nutze dynamic_cast, weil dieser am sichersten ist (RTTI muss eingeschaltet sein).
    Ein einfacher C-Cast funktioniert meistens auch - wenn er aber mal nicht funktioniert, wird es problematisch.

    C...App* pApp = dynamic_cast<C...App*>(AfxGetApp());
    ASSERT(pApp); // zur Sicherheit
    

    3 CMainFrame

    An CMainFrame kommt man mit

    CMainFrame* pFrame = dynamic_cast<CMainFrame*>(AfxGetMainWnd());
    ASSERT (pFrame);
    

    Das ist aber nicht nötig, wenn man nur eine Nachricht senden will, z.B.

    AfxGetMainWnd()->SendMessage(WM_CLOSE);
    AfxGetMainWnd()->SendMessage(WM_COMMAND, ID_FILE_SAVE);
    

    4 C...Doc

    An das Document kommt man mit

    C...Doc* pDoc = dynamic_cast<C...Doc*>(((CMainFrame*)AfxGetMainWnd())->GetActiveDocument());
    ASSERT(pDoc);
    

    Falls man mehrere Dokumente hat (was dann genau genommen aber kein echtes SDI ist), bekommt man damit das aktuell angezeigte.
    Vom Mainframe aus kann man das AfxGetMainWnd weglassen.

    Von der Viewklasse aus gibt es eine "Abkürzung":

    C...Doc* pDoc = dynamic_cast<C...Doc*>(GetDocument());
    ASSERT(pDoc);
    

    5 C...View

    Den View bekommt man mit

    C...View* pView = dynamic_cast<C...View*>(((CMainFrame*)AfxGetMainWnd())->GetActiveView());
    ASSERT(pView);
    

    Falls man mehrere Views hat (was dann genau genommen aber kein echtes SDI ist), bekommt man damit den View, der den Fokus hat.
    Vom Mainframe aus kann man das AfxGetMainWnd weglassen.

    Und das war es auch schon. 🙂
    Mit diesen wenigen Befehlen kommt man von überall her an jede beliebige Klasse und deren Member.

    6 Dialoganwendungen

    Teilweise ist dies auch auf Dialoganwendungen übertragbar:
    Die C...App ist gleich.
    Das Hauptfenster ist der C...Dlg (bei SDI: CMainFrame).
    Doc und View gibt es nicht.



  • Hallo!
    Wenn ich folgenden Ablauf in mein Programm einbaue:
    C...Doc

    An das Document kommt man mit
    C/C++ Code:
    C...Doc* pDoc = dynamic_cast<C...Doc*>(AfxGetMainWnd()->GetActiveDocument());
    ASSERT(pDoc);
    C/C++ Code:
    C...Doc* pDoc = dynamic_cast<C...Doc*>(AfxGetMainWnd()->GetActiveDocument());
    ASSERT(pDoc);
    C/C++ Code:
    C...Doc* pDoc = dynamic_cast<C...Doc*>(AfxGetMainWnd()->GetActiveDocument());
    ASSERT(pDoc);

    Falls man mehrere Dokumente hat (was dann genau genommen aber kein echtes SDI ist), bekommt man damit das aktuell angezeigte.
    Vom Mainframe aus kann man das AfxGetMainWnd weglassen.

    Von der Viewklasse aus gibt es eine "Abkürzung":

    dann sagt mir der Compiler, dass GetActiveDocument() kein Element von CWnd sei.
    Wo ist das Problem?
    Danke!



  • Ich hatte einen Cast vergessen, entschuldige bitte.
    Ich habe es jetzt oben auch reineditiert:

    C...Doc* pDoc = dynamic_cast<C...Doc*>((CMainFrame*)AfxGetMainWnd()->GetActiveDocument());
    


  • wenn ich das les bin ich noch mehr froh, dass es jetzt WinForms gibt ^^



  • hier zur Ergänzung bezüglich SDI mit MFC:
    http://www.henkessoft.de/C++/MFC/mfc_einsteigerbuch_kapitel7.htm



  • Ein interessanter Artikel. Gibt es so eine Gruppierung eigentlich auch für MDI-Projekte?



  • Hi!
    sowohl bei

    C...View* view = dynamic_cast<C...View*>((CMainFrame*)AfxGetMainWnd()->GetActiveView());
    	ASSERT(view);
    

    als auch bei

    C...View* view = dynamic_cast<C...View*>(AfxGetMainWnd()->GetActiveView());
    	ASSERT(view);
    

    gibs den fehler: error C2039: 'GetActiveView': Ist kein Element von 'CWnd'

    was mache ich falsch?


  • Administrator

    Noch eine Ergänzung, aus Codeguru:
    http://www.codeguru.com/forum/showthread.php?t=281430

    Grüssli



  • @Frager: Eine Klammerung zu wenig (am besten kopierst du die richtige Form direkt aus dem Artikel) - op-> hat höhere Priorität als die cast-Operatoren, deshalb muß letzterer eingeklammert werden.



  • Ich hatte es auch nur einmal korrigiert. 🙄
    Irgendwie war bei diesem Artikel der Wurm drin, ich hoffe, jetzt ist endlich alles richtig.



  • Ich habe da mal die Frage, wenn ich eine Anwendung in SDI benötige, die über Threads etwas übers Netzwerk sendet und empfängt, in welcher Klasse erstelle ich die Threads und wie benutze ich diese dann wenn sie über einen BtnKlcik ausgeführt werden sollen?
    Und wo mache ich Initialisierungen, die gemacht werden sollen bevor das Document angezeigt werden soll z.B. beim Auslesen einer Konfigurationsdatei wobei die Werte aus dieser Datei in der View Klasse benötigt wird?

    Was sind hier die allgemeinen Regeln?

    Gruß an alle


Anmelden zum Antworten