Benutzer mit den meisten Antworten
Probleme mit Menüs in MainFrame und Dokument.

Frage
-
Guten Tag,in einer SDI Anwendung habe ich das automatisch generierte Menü im Hauptfenster (Frame Window) im Menü-Editor um ein Menü mit 4 Untermenüs ergänzt. Die Ergänzung liegt hier vor (links) dem Menü "Datei". Die Ereignis-Handler sind in das Dokument verlegt. Aus diesen heraus werden Funktionen einer DLL aufgerufen.
Was mich stört ist, daß nur das erste Submenü beim Start meiner Anwendung freigegeben ist und die anderen 3 Grau, also gesperrt sind. Das ist zwar für den Start in Ordnung, aber nach Benutzung des ersten Submenüs möchte ich nun dieses sperren und zwei weitere freigeben, und daran bin ich bisher gescheitert!!!
Frage:
Wie kann man aus den im Dokument befindlichen Ereignishandler-Funktionen heraus Menüs bzw.
Submenüs im Frame Window (auf MenuBar?) ansprechen?
Mit Menüs in Dialogen ist das relativ einfach! Ein derartiger Aufruf ist zum Beispiel:
BOOL CRLIODlg::OnInitDialog()
{
CMenu* pMenu;
pMenu = GetMenu();
if (pMenu != NULL)
{ // Disable 3 Menüpunkte bei Start der Anwendung
m_pMenu->EnableMenuItem(ID_LI, MF_ENABLED);
m_pMenu->EnableMenuItem(ID_LO, MF_DISABLED | MF_GRAYED);
...
}
...
}
Das funktioniert leider in der Funktion CMainFrame::OnCreate() nicht! Ich bekomme zwar einen Menü-Pointer mit:
pMenu = this->m_wndMenuBar.GetMenu()
aber die erste Verwendung wie oben, geht schief, und aus der Dokumentfunktion heraus habe ich bisher schon überhaupt keinen Erfolg gehabt.
K. H. Renders.
M. Thaddaeus
Antworten
-
Hallo Klaus,
ich hatte es übersehen, sorry. Verwende einfach deine M_bMenuA1, M_bMenuA2, M_bMenuA3 und M_bMenuA4 um den Status der Menüpunkte zu aktualisieren oder setze die m_bMnuA1Flg - m_bMnuA4Flg ebenfalls in deiner Methode. Falls es komplexer ist, kannst Du, so wie ich es Eingangs schrieb, eine Methode benutzen um den Status zu ermitteln, auch dort könntest Du noch den Wert für die m_bMnuA#Flags setzen.
void CDoc::OnUpdateMenuA1(CCmdUI *pCmdUI) { pCmdUI->Enable(IsMnuA1Active()); }
BOOL CDoc::IsMnuA1Active() { return M_bMenuA1; // Oder wie auch immer die Bedingung für true lautet }
Gruß
- Florian
- Bearbeitet Florian Haupt Freitag, 17. Juni 2016 08:59 + void
- Als Antwort markiert m-thaddaeus Montag, 20. Juni 2016 09:04
-
Hallo Klaus,
alles wie bei einer einzelnen ID auch.
Also:ON_UPDATE_COMMAND_UI_RANGE(ID_B1, ID_B3, &CDoc::OnUpdMBRange) ... void CDoc::OnUpdMBRange(CCmdUI *pCmdUI) { pCmdUI->Enable(IsMnuBActive()); }
Der Unterschied ist nur, das deine Memberfunktion für mehrere IDs aufgerufen wird.
Gruß
- Florian
- Bearbeitet Florian Haupt Freitag, 17. Juni 2016 08:58 + void
- Als Antwort vorgeschlagen Dimitar DenkovMicrosoft contingent staff, Administrator Freitag, 17. Juni 2016 13:40
- Als Antwort markiert m-thaddaeus Montag, 20. Juni 2016 09:03
-
Guten Tag Florian,
Dank für Deine baldige Information. Ich habe damit ein wenig herumexperimentiert, kam aber nicht klar. Ich habe es wohl nicht richtig verstanden. Macht nichts, ich habe einen anderen Weg eingeschlagen. Da die Aufrufe alle eine DLL betreffen und diese alle Daten selbst speichert, kann ich die Behandlung von Fehlaufrufen in der DLL selbst durchführen und entsprechende Fehlermeldungen ausgeben. Da benötige ich die Schaltung (Enable/Disable) der Menüpunkte nicht.
Gruß
Klaus.
M. Thaddaeus
- Als Antwort markiert m-thaddaeus Dienstag, 7. Juni 2016 09:14
Alle Antworten
-
Hallo M. Thaddaeus,
den Zustand der Menüeinträge (aktiv/inaktiv) kann man am besten mit MessageMap Einträgen zu ON_UPDATE_COMMAND_UI setzen.
ON_UPDATE_COMMAND_UI(ID_LI, OnUpdateLi)
und dazu die Methode implementieren
void ..::OnUpdateLi(CCmdUI *pCmdUI) { pCmdUI->Enable( IsLiActive() ); }
Gruß
- Florian
- Als Antwort vorgeschlagen Dimitar DenkovMicrosoft contingent staff, Administrator Donnerstag, 2. Juni 2016 14:20
- Als Antwort markiert m-thaddaeus Dienstag, 7. Juni 2016 09:07
- Tag als Antwort aufgehoben m-thaddaeus Dienstag, 7. Juni 2016 09:07
-
Guten Tag Florian,
Dank für Deine baldige Information. Ich habe damit ein wenig herumexperimentiert, kam aber nicht klar. Ich habe es wohl nicht richtig verstanden. Macht nichts, ich habe einen anderen Weg eingeschlagen. Da die Aufrufe alle eine DLL betreffen und diese alle Daten selbst speichert, kann ich die Behandlung von Fehlaufrufen in der DLL selbst durchführen und entsprechende Fehlermeldungen ausgeben. Da benötige ich die Schaltung (Enable/Disable) der Menüpunkte nicht.
Gruß
Klaus.
M. Thaddaeus
- Als Antwort markiert m-thaddaeus Dienstag, 7. Juni 2016 09:14
-
Hallo Klaus,
eigentlich ist das recht Überschaubar und schnell implementiert. Für die Menü-Einträge müsstest Du ganz ähnliche Einträge in der Message Map haben. Da ich nicht weiß wo das Problem lag/liegt, möchte ich noch auf die entsprechenden Themen in der MSDN verweisen - denn Message Handling ist schon ein recht wichtiges Thema und für den Anwender ist es schick, wenn der nicht erst testen muss, ob der Menüeintrag geht.
Zuordnen von Meldungen zu Funktionen
- Florian
-
Guten Tag Florian,
es ist zwar zum Heulen, aber ich komme mit „ON_UPDATE_COMMAND_UI“ zu „Enable“ und „Disable“ meines Menüs einfach nicht klar!!!
Folgendes Menüs habe ich im MainFrame:
MenuA MenuB
MenuA1 MenuB1
MenuA2 MenuB2
MenuA3
MenuA4
Die Eventhändler für diese Menüs befinden sich in meinem Dokument:
CDoc::OnMenuA1() CDoc::OnMenuB1()
... CDoc::OnMenuB1()
...
CDoc::OnMenuA4()
Ebenfalls in meinem Dokument befinden sich die Update Command Handler:
CDoc::OnUpdateMenuA1(CCmdUI *pCmdUI)
{
pCmdUI->Enable(m_bMnuA1Flg);
}
CDoc::OnUpdateMenuA2(CCmdUI *pCmdUI)
{
pCmdUI->Enable(m_bMnuA2Flg);
}
CDoc::OnUpdateMenuA3(CCmdUI *pCmdUI)
{
pCmdUI->Enable(m_bMnuA3Flg);
}
CDoc::OnUpdateMenuA4(CCmdUI *pCmdUI)
{
pCmdUI->Enable(m_bMnuA4Flg);
}
Bei Programmstart sind die 4 boolschen Membervariablen (Dokument) wie folgt gesetzt:
M_bMenuA1 = true; //(Enabled)
M_bMenuA2 = false; //(Disabled)
M_bMenuA3 = false; //(Disabled)
M_bMenuA4 = false; //(Disabled)Das funktioniert bei Start der Anwendung ausgezeichnet! Aber nun kommt der Grund meiner grauen Haare:Mit Klick der linken Maustaste auf z. B. MenuA1 wird dessen Ereignishandler aufgerufen. Abhängig vom Ergebnis eines Funktionsaufrufes in demselben möchte ich nun die Menüs wie folgt setzen:
CDoc::OnMenuA1()
{
if (Function())
{
M_bMenuA1 = false; //(Disabled)
M_bMenuA2 = true; //(Enabled)
M_bMenuA3 = true; //(Enabled)
M_bMenuA4 = true; //(Enabled)
// jetzt muß ich nun irgendwie die 4 Update Command Handler
// aufrufen, aber wie???????
}
}
Ich finde einfach im Internet keinen brauchbaren Hiweis. Darüber hinaus möchte ich auch noch das ganze MenuB umschalten können. Das ist das nächste Problem was mir droht.
Kannst Du mir helfen?
Gruß
Klaus.M. Thaddaeus
-
Guten Morgen Klaus,
CDoc::OnMenuA1()
{
if (Function())
{ M_bMenuA1 = false; //(Disabled) M_bMenuA2 = true; //(Enabled) M_bMenuA3 = true; //(Enabled) M_bMenuA4 = true; //(Enabled) // jetzt muß ich nun irgendwie die 4 Update Command Handler // aufrufen, aber wie???????
}
}Den Aufruf übernimmt das Framework, Du musst Dich dort um nichts weiter kümmern. Alles was getan werden muss sind die MessageMap Einträge und die MessageHandler, in welchen Du die Menüeinträge mittels der booleschen Variablen aktualisierst - Das reicht. Die Menüeinträge werden beim aufklappen des Menüs aktualisiert (siehe auch MSDN: Wann müssen Updatehandler aufgerufen werden?).
Gruß- Florian
-
Guten Morgen Florian,
danke, daß Du Dich weiter um mich kümmerst. Dein Hinweis, daß ich mich in OnMenuA1 um nichts kümmern muß, funktioniert leider nicht! Dieser Handler wird durch den Mausklick auf Menüpunkt MenuA1 aufgerufen. Beim Aufklappen des Menüs allerdings sind meine boolschen Variablen noch nicht aktualisiert, denn das geschieht ja erst nach Rückgabe aus der in OnMenuA1 aufgerufenen Funktion. Somit muß ich die Möglichkeit haben, direkt nach der Aktualisierung der boolschen Variablen die 4 Handler aufzurufen.
Den von Dir angegebenen MSDN Artikel habe ich gelesen, aber der hilft auch nicht weiter! Es muß doch irgendeine Möglichkeit geben, die Menüs von wo aus auch immer schalten zu können. Ich weiß jedenfalls nicht weiter!
Gruß
Klaus.M. Thaddaeus
-
Hallo Klaus,
ich hatte es übersehen, sorry. Verwende einfach deine M_bMenuA1, M_bMenuA2, M_bMenuA3 und M_bMenuA4 um den Status der Menüpunkte zu aktualisieren oder setze die m_bMnuA1Flg - m_bMnuA4Flg ebenfalls in deiner Methode. Falls es komplexer ist, kannst Du, so wie ich es Eingangs schrieb, eine Methode benutzen um den Status zu ermitteln, auch dort könntest Du noch den Wert für die m_bMnuA#Flags setzen.
void CDoc::OnUpdateMenuA1(CCmdUI *pCmdUI) { pCmdUI->Enable(IsMnuA1Active()); }
BOOL CDoc::IsMnuA1Active() { return M_bMenuA1; // Oder wie auch immer die Bedingung für true lautet }
Gruß
- Florian
- Bearbeitet Florian Haupt Freitag, 17. Juni 2016 08:59 + void
- Als Antwort markiert m-thaddaeus Montag, 20. Juni 2016 09:04
-
Hallo Florian,
tut mit leid, geht nicht! Das funktioniert nur, wenn die OnUpdate... Handler selbst aus dem Framework oder von sonst woher aufgerufen werden. Die Handler werden über das Framework leider nur dann aufgerufen, wenn man mit der Maus das Menü aufklappen will und sonst nicht!
Aus dem Framework heraus wird anscheinend eine Meldung gesendet, vermutlich WM_INITMENUPOPUP mit irgendwelchen Parametern in hWnd, wParam und lParam, weiß der Geier mit welchen. Ich habe das bereits einmal versucht, ist aber auch fehlgeschlagen, da ich wParam= lParam=0 übergeben habe. als Fensterhandle habe ich hMainFrame übergeben was möglicherweise auch falsch war. Keene Ahnung nich! Ich weis wirklich nicht wie ich daran kommen soll.
Gruß
KlausM. Thaddaeus
-
Die Handler werden über das Framework leider nur dann aufgerufen, wenn man mit der Maus das Menü aufklappen will und sonst nicht!
Ja? Und wann sonst braucht man einen aktuellen Zustand bei den Menüpunkten?
Verstehe das Problem gerade überhaupt nicht, solange das Menü nicht sichtbar ist, brauchen die Einträge auch keinen Zustand, beim aufklappen wird dieser via ON_UPDATE_COMMAND_UI aktualisiert, das sollte also absolut reichen.Ich wüsste auch nicht wie ein UI Update für Elemente funktionieren sollte die quasi gerade nicht existieren, bzw. inwiefern deren potentieller Zustand relevant sein sollte (den ja bis zum aufklappen des Menüs kein Benutzer sehen kann).
Der klassische Weg um eine Aktualisierung im aktuellen Fenster zu erreichen ist der Aufruf von Invalidate(), wobei sich dies sicher nicht auf die nicht sichtbaren Menüs auswirkt.
- Florian
-
Guten Morgen Florian,
Du hast ja sooo recht! Entschuldige, ich hatte einen dicken Flüchtigkeitsfehler in meinem Programm. Den verrate ich Dir allerdings nicht, da Du mich sonst endgültig für bescheuert hältst! Jedenfalls hätte ich mich auch vergaggeiert gefühlt. Jedenfalls funktioniert das nun - wie Du es vorausgesagt hast - einwandfrei. Danke!
Nun aber zu meinem zweiten Problem: Du erinnerst Dich,
MenuA MenuB <-----
MenuA1 MenuB1
MenuA2 MenuB2
MenuA3
MenuA4Ich möchte nun aus meinem Dokument heraus auch noch das bzw. die weiteren Menüs (MenuB ...) komplett ein-/ausschalten, denn wenn ich in diesen jeden einzelnen Menüpunkt wie gehabt behandeln muß ist das ein ganz schöner Aufwand. Bei Dialogen geht das einfach folgendermaßen:
m_pMenu->EnableMenuItem(1, MF_BYPOSITION | MF_DISABLED | MF_GRAYED);
DrawMenuBar();und das war's. Das funktioniert aber in MainFrame nicht. Wie macht man das?
Gruß
Klaus.M. Thaddaeus
-
Guten Morgen Klaus,
wenn Du eine Reihe von aufeinanderfolgenden Menüeinträgen aufgrund einer Bedingung aktivieren/deaktivieren möchtest, dann ist dafür ON_UPDATE_COMMAND_UI_RANGE die geeignete Wahl. Wichtig dabei, deine Menüeinträge müssen mit aufeinanderfolgenden IDs versehen sein, dann kannst Du im Range einfach von ID_MENUB1 - ID_MENUBN als Range angeben und alle Einträge können in einer Methode bearbeitet werden.
Gruß
- Florian
-
Guten Morgen Florian,
et jeht schon widder loss!
MenuB
MenuB1 ID_B1 1001
MenuB2 ID_B2 1002
MenuB3 ID_B3 1003
Meine Vorlagen waren:
Deine Antwort und
https://msdn.microsoft.com/en-us/library/84xtde24(v=vs.100).aspx
afx_msg void OnUpdMBRange(UINT nID)
Was der "UINT nId" Parameter bedeutet ist mir auch unklar.BEGIN_MESSAGE_MAP
...
ON_UPDATE_COMMAND_UI_RANGE(ID_B1, ID_B3, &CDoc::OnUpdMBRange)
END_MESSAGE_MAP
void OnUpdMBRange(UINT nID)
{}
Compilierversuch brachte den Fehler:
error C2440: 'static_cast': 'void (__thiscall CDoc::* )(UINT)' kann nicht in 'void (__thiscall CCmdTarget::* )(CCmdUI *)' konvertiert werden
1> Umwandlung von der Basis in die Ableitung erfordert 'dynamic_cast' oder 'static_cast'
Wat nu? Wo liegt hier wieder mein Fehler? Leider habe ich auch nichts besseres als o. a. MSDN Seite gefunden, komme aber gedanklich damit in sofern nicht klar, daß ich nirgendwo sehe wie diese Funktion an CCmdUI kommt und wie die weitere Verarbeitung aussehen muß.
Gruß
Klaus.M. Thaddaeus
-
Hallo Klaus,
alles wie bei einer einzelnen ID auch.
Also:ON_UPDATE_COMMAND_UI_RANGE(ID_B1, ID_B3, &CDoc::OnUpdMBRange) ... void CDoc::OnUpdMBRange(CCmdUI *pCmdUI) { pCmdUI->Enable(IsMnuBActive()); }
Der Unterschied ist nur, das deine Memberfunktion für mehrere IDs aufgerufen wird.
Gruß
- Florian
- Bearbeitet Florian Haupt Freitag, 17. Juni 2016 08:58 + void
- Als Antwort vorgeschlagen Dimitar DenkovMicrosoft contingent staff, Administrator Freitag, 17. Juni 2016 13:40
- Als Antwort markiert m-thaddaeus Montag, 20. Juni 2016 09:03
-
Hallo Florian,
Donnerwetter! Auch das klappt! Herzlichen Dank! Ich kann nun mit meinen Menüs schalten und walten. Du hast nun beste Aussicht mit Fragen über dieses Thema von mir nicht mehr belästigt zu werden. Nochmals Dank für Deine Mühe.
Gruß
Klaus.M. Thaddaeus
-
Hallo Klaus,
Wenn Florians Beiträge Dir weitergeholfen haben, markiere bitte diese, die die Lösung enthalten, als Antwort. Das hilft auch anderen Nutzern, die ein ähnliches Anliegen haben. Ich verweise Dich auf die Forenregeln:
· Lösungsbeiträge als “Die Antwort“ markieren
Bitte markieren Sie den Beitrag, der zur Lösung geführt hat, als "Die Antwort". Durch Bewerten eines Beitrags als "Die Antwort" können andere Teilnehmer die Lösung schneller finden. Außerdem können Sie dem Benutzer, der die Antwort eingereicht hat, für seinen Beitrag danken und zur Steigerung der Antwortqualität in der Diskussionsgruppe beitragen.
[Quelle: Forenregeln]Gruß,
DimitarBitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip „IT-Pros helfen IT-Pros“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.