Controls in einem Fenster abklappern und casten
-
Hallo!
Ich möchte in einem Dialog durchlaufen und alle Eingabefelder,
Knöpfe ... deaktivieren. Dabei sollen CStatic-Objekte nicht deaktiviert
werden und CEdit-Felder nur Read-Only sein. Dazu muß ich offenbar casten...void CMeinDialog::setReadOnly() { CWnd *win = GetTopWindow(); while( win ) { CRuntimeClass *myClass = win->GetRuntimeClass(); TRACE("%s\n",myClass->m_lpszClassName); if(win->IsKindOf( RUNTIME_CLASS(CEdit) ) ) win->EnableWindow( false ); win = win->GetNextWindow(); } }
Das funktioniert schonmal nicht. Die Trace-Zeile leifert immer nur "CTempWnd".
Warum, habe ich hier erfahren:http://www.fun-soft.de/showtopic.php?threadid=8788
www.microsoft.com/msj/0997/c0997.aspxWie komme ich nun aber an die "echten" Objekte?
Viele Grüße,
Ulf
-
Vielleicht kannst du dir da was abgucken:
http://www.c-plusplus.net/forum/viewtopic-var-t-is-56428.html
-
Hallo!
Ohne Garantie: Versuch mal das:
void CMeinDialog::setReadOnly() { CWnd *win = GetTopWindow(); while( win ) { CEdit* pEdit = dynamic_cast<CEdit*>(win); if(pEdit) win->EnableWindow( false ); win = win->GetNextWindow(); } }
Irgendwie geht sowas aber, ich hab das schon mal gesehen...
-
Die Sache scheint zu funktionieren. Ich habe sie mir angepaßt
(Static-Texte bleiben aktiv, "Cancel"-Knopf auch) und es geht.
Ob der Code ganz sauber ist, weiß ich allerdings noch nicht.
Folgender Abschnitt aus meinem zweiten obengenannten Link
macht mir Sorgen (der Text war sehr lang daher das Zitat):This is a common source of confusion to beginning MFC programmers.
I've often seen code like this:CMyDialog::SomeFn(...) { CEdit* pEdit = (CEdit*)GetDlgItem(ID_EDIT1); // NOT!! pEdit->GetSel(...); • • • }
Technically, this code is incorrect because—once again, assuming you haven't created a CEdit for the ID_EDIT1 control—GetDlgItem returns a CWnd, not a CEdit. You can cast to CEdit all you like, but the object is still a CWnd. In practice, however, this code works because all CEdit::GetSel does is send EM_GETSEL to the window, which, being a true edit control, it responds to. But if GetSel was a virtual function instead of a wrapper, or if it used some data member that was specific to CEdit, this code would crash.
In short, MFC creates temporary window objects only so you can then pass them immediately to other MFC functions that require CWnds. What does this mean to you? As a practical matter, it means that you should never store a pointer to a temporary window.Das Problem trifft doch auch auf Eure Beispiele zu, oder?
Vielen Dank,
Ulf
-
Der dynamic_cast gibt NULL zurück, wenn das was anderes als ein CEdit ist.
Hat der Versuch denn funktioniert? Oder machst du es wie in dem Beispiel?
-
Ein dynamic_cast geht nicht, da das Objekt, das GetTopWindow() zurückgibt
nur ein CTempWnd ist. Da kommt beim casten immer NULL raus. Ein static_cast
macht daraus gewaltsam z.B. ein CEdit. Im Grunde ist es aber keines, da das
Objekt nur ein temporär erzeuges CWnd ist. Es funktioniert trotzdem, da wir
Messages an das Objekt schicken, die trotzdem verarbeitet werden. Bei anderen
Aktionen kann das schiefgehen. Das ganze liegt daran, daß die Klassen auf ein
altes System aufgepfropft wurden.
Die Erläuterung findet ihr in dem genannten Artikel.
Das Beispiel aus dem Forum habe ich etwas modifiziert, womit es
sicherer laufen sollte. Ich schicke die Nachricht direkt, ohne
CEdit-spezifische Funktionen aufzurufen.BOOL CALLBACK MeinDialog::DisableControl( HWND hwnd, LPARAM lParam ) { CWnd* pcWnd = FromHandle(hwnd); TCHAR cClassName[255]; memset(cClassName, 0, sizeof(cClassName)); GetClassName(hwnd, cClassName, sizeof(cClassName)); // Klassenname holen CString strClassName = cClassName; // ------ einige Controls nicht deaktivieren --------- if( pcWnd->GetDlgCtrlID()==IDCANCEL ) { pcWnd->EnableWindow( true ); return TRUE; } // ------------ Wenn 1 dann setze disabled ------------- if(lParam==1) { if(strClassName == "Static") // Static nicht ändern { return TRUE; } if(strClassName == "Button" && // Rahmen nicht ändern (pcWnd->GetStyle()&BS_GROUPBOX)==BS_GROUPBOX ) { return TRUE; } if(strClassName == "Edit") // Edit schreibschützen { pcWnd->SendMessage( EM_SETREADONLY, true, 0 ); return TRUE; } pcWnd->EnableWindow(FALSE); } // --- Wenn was anderes als 1 dann setze enabled ------ else { if(strClassName == "Edit") { pcWnd->SendMessage( EM_SETREADONLY, false, 0 ); return TRUE; } pcWnd->EnableWindow(TRUE); } return TRUE; }
Static- und Group-Controls werden nicht deaktiviert (Group-Controls sind CButton mit der Eigenschaft BS_GROUPBOX). Der Cancel-Knopf wird auch
ausgeschlossen, damit wir den Dialog noch verlassen können.Gruß,
Ulf
-
Falls das jemand auch so sieht, könnte man die FAQ updaten:
http://www.c-plusplus.net/forum/viewtopic-var-t-is-56428.html