[Menüleiste] Callbacks werden nicht immer ausgeführt
-
Hallo Community,
in meinem aktuellen Software-Projekt kommt es zu einem seltsamen Verhalten, das ich mir nicht erklären kann und deshalb um Hilfe bitte.
Die Anwendung besitzt eine Menüleiste, die unter dem Menüpunkt File einen Unterpunkt Workspace beinhaltet. Durch Anklicken des Unterpunktes Workspace öffnet sich ein modaler Dialog der eine Verzeichnisauswahl ermöglicht. Nachdem ein Verzeichnis ausgewählt wurde öffnet sich daraufhin ein ListView.
So weit, so gut.
Jetzt ist es aber so, dass ein erneutes Öffnen des Menüpunktes File und anschließendes Anklicken des Unterpunktes Workspace den hinterlegten Callback zur Öffnung des modalen Dialogs nicht ausführt. Schließe ich das ListView-Fenster geht es allerdings wieder.Kennt jemand diese Problematik, oder hat einen Anhaltspunkt an welcher Stelle man am besten versuchen könnte das Verhalten der Software nachzuvollziehen?
Freundliche Grüße,
Jas
-
Schau mal nach der ID dieses Commands. Du hast vermutlich in einem View die ID nochmal vergeben und einen Handler dafür definiert.
-
Hallo Martin,
die Vermutung hatte ich auch schon, allerdings kann ich keine nochmalige Vergabe der Command-ID ausfindig machen.
Eine weitere Beobachtung die ich soeben machen konnte, ist, dass offenbar jedes weitere MDI-Fenster unterhalb des File Menüpunktes eingehängt wird. Das wird doch standardmäßig unter dem Menüpunkt Ansicht eingehängt, oder?
-
Dann schau mal in die resource.h rein ob evtl. zwei unterschiedliche Symbole die selbe ID haben!
Bzgl. MDI Nein: Fenster
-
Hallo Martin,
Symbole mit gleicher ID sind in der Resource.h nicht vorhanden.
Dass die geöffneten MDI-Fenster unter den File-Menüpunkt gehängt werden ist aber doch auch nicht korrekt. Ist das vielleicht ein Anhaltspunkt der die Fehlersuche vereinfachen könnte?
-
Du kannst einfach mal den Debugger benutzten und OnCmdMsg in Deinem CMainFrame durch debuggen, wenn die ID angeklickt wird.
CMDIFRame::OnCmdMsg ist verantwortlich für das Routing des Commands.Ansonsten schau in CMDIFrameWnd::GetWindowMenuPopup.
Das Menü, das ein Command Id nID >= AFX_IDM_WINDOW_FIRST && nID <= AFX_IDM_WINDOW_LAST hat ist das Fenster Menü.Ich würde mal sagen Deine gesamten IDs sind etwas durcheinander.
Anmerkung:
#define AFX_IDM_WINDOW_FIRST 0xE130
#define AFX_IDM_WINDOW_LAST 0xE13FDir ist auch klar, dass es resevierte ID Bereiche gibt? (siehe TN).
-
Hallo Martin,
ich habe OnCmdMsg() in der MainFrame-Klasse überladen, allerdings fällt es mir schwer das Anklicken der ID abzufangen, da der Breakpoint bereits erreicht wird, wenn ich den Menüpunkt File anklicke, und ich somit garnicht mehr dazu komme, den Menü-Unterpunkt Workspace anzuklicken.
-
Du kannst doch den Breakpoint so setzen, dass er nur bei der ID zuschlägt. Zudem hättest Du das nicht überladen brauchen.
Du kanst auch im MFC Source Code einen BP setzen.
-
Hallo Martin,
der Code der überladenen OnCmdMsg()-Methode sieht so aus:
BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void *pExtra, AFX_CMDHANDLERINFO *pHandlerInfo) { if (nID == ID_VUE_WORKSPACE) __super::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); return TRUE; }Wobei ID_VUE_WORKSPACE die vom Resourcen-Editor vergebene ID des Untermenüpunktes Workspace ist. Setze ich den Breakpoint in den if-Block, dann wird der Breakpoint allerdings schon erreicht, sobald ich in der Menüleiste auf File klicke.
-
Das ist korrekt. Denn in diesem Fall wird der OnUpdate Handler gesucht.
Schau mal die die Doku an zu OnCmdMsg
Wenn DU nur das Command Debuggen möchtest ist nCode CN_COMMAND!
-
Hallo Martin,
wenn ich das if-Statement folgendermaßen ändere:
if (nID == ID_VUE_WORKSPACE && nCode == CN_COMMAND) { ... }wird der Breakpoint nach wie vor schon beim Klick auf File erreicht.
-
Komisch. Ist ja auch wurscht. Debugge in die Funktion und schau noch wo der Handler das UI enabled.
Den er findet ja einen Handler.
-
Hallo Martin,
vielen Dank für die geduldige Hilfe. Das Debuggen der OnCmdMsg-Nachrichtenkette hat den Fehler offenbart.
-
Und hatte ich Recht?
War doch ein Handler drin?
-
Hallo Martin,
ja, Dein Tipp war richtig. Allerdings war es nicht ganz so einfach herauszufinden, weil Teile der GUI und deren Callbacks generisch über XML-Dateien erzeugt werden.
-
Hallo Community,
ich bin's nochmal. Leider besteht nach wie vor das Problem, dass die Liste der geöffneten MDI-Fenster unter den ersten Menüpunkt gehängt wird.
Laut Internet-Recherche soll eine mögliche Lösung darin liegen, die Funktion GetWindowMenuPopup() der Klasse CMDIFrameWnd zu überschreiben. Jetzt habe ich beim Debuggen festgestellt, dass weder die überschriebene, noch die Funktion der Basisklasse aufgerufen werden, wenn im Menü navigiert wird.Für Ideen und Hinweise bin ich, wie immer, dankbar.
[edit]
Offenbar wird die Funktion nicht automatisch aufgerufen, das geschieht jetzt allerdings durch einen expliziten Aufruf:
CMenu* menubar = GetMenu(); CMenu* wmenu = CMenu::FromHandle(GetWindowMenuPopup(menubar->GetSafeHmenu()));Nach diesem Aufruf ist wmenu == NULL, trotzdem werden die aktiven MDI-Fenster eingehängt.
[/edit]
Freundliche Grüße,
Jas
-
Du sollst das icht überschreiben.
Hier nochmal was ich geschrieben habe:Ansonsten schau in CMDIFrameWnd::GetWindowMenuPopup.
Das Menü, das ein Command Id nID >= AFX_IDM_WINDOW_FIRST && nID <= AFX_IDM_WINDOW_LAST hat ist das Fenster Menü.Ich würde mal sagen Deine gesamten IDs sind etwas durcheinander.
Anmerkung:
#define AFX_IDM_WINDOW_FIRST 0xE130
#define AFX_IDM_WINDOW_LAST 0xE13FDir ist auch klar, dass es resevierte ID Bereiche gibt? (siehe TN).
Du benötigst einen DummyEintrag in dem fenster Menü.
-
Hallo Martin,
ich habe den expliziten Aufruf der Funktion wieder heraus genommen.
Wenn ich einen Breakpoint in die CMDIFrameWnd::GetWindowMenuPopup(HMENU hMenuBar) Funktion setze, wird dieser Breakpoint nie erreicht.
-
Hast Du OnCreateClient überschrieben und rufst evtl. nicht die Funktion der Elternklasse auf?
Debugge mal in die Funktion und schau Dir die CreateClient Implementierung an.
-
Hallo Martin,
CMDIFrameWnd::OnCreateClient(...) wird nicht überschrieben.
Das Debuggen in die CMDIFrameWnd::OnCreateClient(...) Methode, bzw. in die CMDIFrameWnd::CreateClient(...) Methode habe ich gemacht.Ich fürchte ich verstehe allerdings nicht ganz worauf Du hinaus willst.