Eigene CDialog-Klasse. Nun davon nochmals ableiten. Wie?
-
Hallo
Vielleicht ists wirklich trivial, aber in Büchern und hier hab ich bisher noch keine Lösung gefunden.
also, ich habe eine Dialogklasse z.B.
class CDlg_CalcMain : public CDialog
jetzt will ich einen weiteren Dialog, der die eigenen Methoden etc. von meiner 'CDlg_CalcMain' Klasse erbt.
Wie kann ich das anstellen?
Ich habe also mittels dem Ressourceneditor einen weiteren Dialog eingefügt und eine Klasse erstellt. Der Klassenassistent gewährt mir nur die Basisklassenauswahl der MS Klassen. Also übernhme ich den CDialog Vorschlag.
class CDlg_SubCalc : public CDialog
..ändere jedoch die Basisableitung in 'CDlg_CalcMain'
Es funktioniert nicht wirklich. Das Ergebnis bringe ich dann soweit zustande, dass wenn ich eine Instanz von meiner Subklasse 'CDlg_SubCalc' erstelle und 'DoModal()' aufrufe, dass der Dialog meiner Hauptklasse angezeigt wird.
Wer weiss Rat?
-
Wenn du die Basisklasse auf CalcMain änderst (was du machen solltest), mußt du auch in verschiedenen MFC-Macros die geädnerte Basisklasse angeben.
Für einen normalen Dialgo ist das nur
BEGIN_MESSAGE_MAP(CDlgSubCalc, /*CDialog ==> */ CDlgMainCalc)
Dann sollte alles funktionieren - allerdings bringst du den Clazz wizard aus dem Takt (der weiß jetzt nicht mehr, daß CDlgSubCalc ein Dialog ist). Lösung:
#define CDialog CDlgMainCalc BEGIN_MESSAGE_MAP(CDlgSubCalc, CDialog) ... END_MESSAGE_MAP() #undef CDialog // nicht vergessen!!!
-
peterchen schrieb:
Dann sollte alles funktionieren - allerdings bringst du den Clazz wizard aus dem Takt (der weiß jetzt nicht mehr, daß CDlgSubCalc ein Dialog ist).
Das bringt leider nicht den gewünschten Erfolg. Kannst du es bitte nochmals anschauen?
Vielleicht mache ich auch etwas mit dem Konstruktor falsch.
Hier der Code:
include "Dlg_CalcMain.h" // headerfile für subdialg class CDlg_Sub : public CDlg_CalcMain { // Konstruktion public: CDlg_Sub(CWnd* pParent = NULL); // Standardkonstruktor // Dialogfelddaten //{{AFX_DATA(CDlg_Sub) enum { IDD = IDD_DIALOG4 }; // HINWEIS: Der Klassen-Assistent fügt hier Datenelemente ein //}}AFX_DATA // Überschreibungen // Vom Klassen-Assistenten generierte virtuelle Funktionsüberschreibungen //{{AFX_VIRTUAL(CDlg_Sub) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-Unterstützung //}}AFX_VIRTUAL // Implementierung protected: // Generierte Nachrichtenzuordnungsfunktionen //{{AFX_MSG(CDlg_Sub) // HINWEIS: Der Klassen-Assistent fügt hier Member-Funktionen ein //}}AFX_MSG DECLARE_MESSAGE_MAP() }; //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ fügt unmittelbar vor der vorhergehenden Zeile zusätzliche Deklarationen ein. #endif // AFX_DLG_SUB4_H__CD95CC1C_16A3_4EED_8AA3_18402A297597__INCLUDED_
Implementierung (Vielleicht habe ich zuviel beim Constructor gelöscht?)
///////////////////////////////////////////////////////////////////////////// // Dialogfeld CDlg_Sub #define CDialog CDlg_CalcMain CDlg_Sub4::CDlg_Sub(CWnd* pParent /*=NULL*/) { //{{AFX_DATA_INIT(CDlg_Sub) // HINWEIS: Der Klassen-Assistent fügt hier Elementinitialisierung ein //}}AFX_DATA_INIT } void CDlg_Sub::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CDlg_Sub) // HINWEIS: Der Klassen-Assistent fügt hier DDX- und DDV-Aufrufe ein //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CDlg_Sub, CDlg_CalcMain) //{{AFX_MSG_MAP(CDlg_Sub) // HINWEIS: Der Klassen-Assistent fügt hier Zuordnungsmakros für Nachrichten ein //}}AFX_MSG_MAP END_MESSAGE_MAP()
Wenn ich nun im Hauptdialog den Code
CDlg_Sub dlg; dlg.DoModal();
ausführe, dann erscheint nochmals der hauptdialog als fenster. huh, was ist denn ds?
-
Ach ja - der resourcen-ID
// hinzufügen: CDlgMain CTor CDlgMainCalc::CDlgMainCalc(UINT resID, CWnd * parent) : CDialog(resID, parent) {} // in CDlgSubCalc einfügen: enum {IDD = IDD_MEIN_ZWEITER_DIALOG }; // ändern: CDlgSub CTor CDlgSubCalc::CDlgSubCalc(CWnd * parent /* = NULL */) : CDlgMainCalc(CDlgSubCalc::IDD, parent)
-
peterchen schrieb:
Ach ja - der resourcen-ID
// hinzufügen: CDlgMain CTor CDlgMainCalc::CDlgMainCalc(UINT resID, CWnd * parent) : CDialog(resID, parent) {} // in CDlgSubCalc einfügen: enum {IDD = IDD_MEIN_ZWEITER_DIALOG }; // ändern: CDlgSub CTor CDlgSubCalc::CDlgSubCalc(CWnd * parent /* = NULL */) : CDlgMainCalc(CDlgSubCalc::IDD, parent)
jo das scheint schon recht ordentlich zu klappen - thanks a million. aber es ist noch nicht ganz richtig: bei DoDataExchange stürzt das Ding auch immer ab (wenn man zuvor das Objekt mit new erzeugt hat). ...
ich konnte eruieren, wo der Fehler erscheint:
// Methode in Hauptdialg ''
void CDlgMainCalc::DoDataExchange(CDataExchange* pDX){ AfxMessageBox("okay-1"); CDialog::DoDataExchange(pDX); AfxMessageBox("okay-2"); //{{AFX_DATA_MAP(CDlgMainCalc) DDX_Control(pDX, IDC_BT_EXIT, m_BtExit); DDX_Control(pDX, IDC_TAB1, m_Tab); //}}AFX_DATA_MAP AfxMessageBox("okay-3"); }
die ersten beiden MsgBoxen erscheinen (ok1, ok2), dann gibts nen Absturz.
Wie zu erkennen ist, verwende ich innerhalb der Haupt-Dialog-Klasse zwei Elemente (Button, Tab-Ctrl).
okay, also ich rufe bei der sub-dialog-klasse die DoDataExchange() auf, kemmentiere allerdings den Aufruf der Basis-Methode aus:
void CDlg_Sub::DoDataExchange(CDataExchange* pDX){ // ausklammern der unteren zeile //CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CDlg_Sub4 // HINWEIS: Der Klassen-Assistent fügt hier DDX- und DDV-Aufrufe ein //}}AFX_DATA_MAP }
jetzt würde das Prog nicht abstürzen, doch welche Konsequenz hat das nun für mich?
Please, more help
ich schnalls echt nicht.
-
(1) Was ist der "Absturz"? (_Assert, Access Violation, ..?)
Die Dialog-Resource hat IDC_BT_EXIT und m_Tab?
Du mußt das DDX + Member aufspalten:
Basis-Dialog hat nur DDX-Einträge für die controls, die auch in der Basis-Dialogresource enthalten sind.
Abgeleiteter Dialog har DDX-Einträge für die hinzugekommenen Controls, und ruft Basisklasse auf.void CDlgMainCalc::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); // aufruf der Basisklasse... //{{AFX_DATA_MAP(CDlgMainCalc) DDX_Control(pDX, IDC_BT_EXIT, m_BtExit); // control / resource von MainCalc //}}AFX_DATA_MAP } void CDlgCalcSub::DoDataExchange(CDataExchange* pDX) { CDlgMainCalc::DoDataExchange(pDX); // aufruf der Basisklasse... //{{AFX_DATA_MAP(CDlgCalcSub) DDX_Control(pDX, IDC_TAB1, m_Tab); // control / resource von SubCalc //}}AFX_DATA_MAP }
-
peterchen schrieb:
(1) Was ist der "Absturz"? (_Assert, Access Violation, ..?)
Das Ding stützt hier ab..
HWND CDataExchange::PrepareCtrl(int nIDC){ TRACE1("Error: no data exchange control with ID 0x%04X.\n", nIDC); ASSERT(FALSE); }
peterchen schrieb:
Die Dialog-Resource hat IDC_BT_EXIT und m_Tab?
Also der MainDlg hat zwei member variablen: Ein Button und ein Tab-Ctrl (IDC_BT_EXIT und IDC_TAB1).
peterchen schrieb:
Du mußt das DDX + Member aufspalten:
Naja, die Einträge hat der Assistent gemacht, wie soll ich die den selber auftrennen?
peterchen schrieb:
Basis-Dialog hat nur DDX-Einträge für die controls, die auch in der Basis-Dialogresource enthalten sind.
Abgeleiteter Dialog har DDX-Einträge für die hinzugekommenen Controls, und ruft Basisklasse auf.Das leuchtet mir sehr ein! In der Basis ist das somit ein Button und ein Tab. Der Subdialog hat z.Z. noch keine eigene Controlls.
peterchen schrieb:
void CDlgMainCalc::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); // aufruf der Basisklasse... //{{AFX_DATA_MAP(CDlgMainCalc) DDX_Control(pDX, IDC_BT_EXIT, m_BtExit); // control / resource von MainCalc //}}AFX_DATA_MAP } void CDlgCalcSub::DoDataExchange(CDataExchange* pDX) { CDlgMainCalc::DoDataExchange(pDX); // aufruf der Basisklasse... //{{AFX_DATA_MAP(CDlgCalcSub) DDX_Control(pDX, IDC_TAB1, m_Tab); // control / resource von SubCalc //}}AFX_DATA_MAP }
Ja das müsste eigentlich so auch gehen, aber es stürzt leider trotzdem ab. Ich habe das Problem behoben, wenn ich im Subdialog nicht die DoDataExchange() von der Haupt-Dialog-Klasse aufrufe, sondern direkt jene von CDialog:
// stürzt ab! void CDlgCalcSub::DoDataExchange(CDataExchange* pDX){ CDlgMainCalc::DoDataExchange(pDX); // aufruf der Basisklasse... //{{AFX_DATA_MAP(CDlgCalcSub) //}}AFX_DATA_MAP }
// funktioniert. aber ist das korrekt so? void CDlgCalcSub::DoDataExchange(CDataExchange* pDX){ CDialog::DoDataExchange(pDX); // aufruf der Haupt-Basisklasse (also CDialog) //{{AFX_DATA_MAP(CDlgCalcSub) //}}AFX_DATA_MAP }
-
peterchen schrieb:
(1) Was ist der "Absturz"? (_Assert, Access Violation, ..?)
Die Dialog-Resource hat IDC_BT_EXIT und m_Tab?
Du mußt das DDX + Member aufspalten:
Basis-Dialog hat nur DDX-Einträge für die controls, die auch in der Basis-Dialogresource enthalten sind.
Abgeleiteter Dialog har DDX-Einträge für die hinzugekommenen Controls, und ruft Basisklasse auf.void CDlgMainCalc::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); // aufruf der Basisklasse... //{{AFX_DATA_MAP(CDlgMainCalc) DDX_Control(pDX, IDC_BT_EXIT, m_BtExit); // control / resource von MainCalc //}}AFX_DATA_MAP } void CDlgCalcSub::DoDataExchange(CDataExchange* pDX) { CDlgMainCalc::DoDataExchange(pDX); // aufruf der Basisklasse... //{{AFX_DATA_MAP(CDlgCalcSub) DDX_Control(pDX, IDC_TAB1, m_Tab); // control / resource von SubCalc //}}AFX_DATA_MAP }
Wenn ich den Code wie oben ändere Stürzt das Programm ab, kannst du mir da weiterhelfen?
vielleicht sollte ich noch erwähnen, dass die Hauptklasse bereits mittels 'DoModal()' aufgerufen wurde.Hintergrund: Mein Main-Dlg hat ein TabCtrl und darin sollen sich weitere Dialoge befindet, sie funktionen von Main erben.
thanks for the help