Menüs
Kommen wir nun zu einer der wichtigsten Ressource, dem Menü. Damit es bei der
folgenden Behandlung der Menüs zu keinen Missverständnissen kommt, zunächst die
Erläuterung einiger wichtiger Begriffe:
|
Begriff
|
Bedeutung
|
| Menü |
Menübalken, besteht in der
Regel aus mehreren Popup-Menüs. |
| Popup-Menü |
Besteht aus einer Beschriftung
(im Menübalken) sowie einem
aufklappbaren Menüfeld mit Menüeinträgen. |
| Menüeintrag |
Einzelner Eintrag innerhalb
eines Popup-Menüs. |

Und auch hier werden wir uns zunächst ansehen, wie ein Menü erstellt bzw. erweitert
wird.
 |
Erstellen Sie zunächst wieder ein neues SDI-Projekt mit dem
Namen Menu. Nach dem der Anwendungs-Assistent seine Arbeit beendet
hat, gehen Sie in die Ressourcen-Ansicht. Öffnen Sie dort den Ressource-Typ
Menu. Sie werden feststellen, dass der Anwendungs-Assistent Ihrem Projekt
schon ein Menü mit der ID IDR_MAINFRAME hinzugefügt hat. Führen Sie jetzt einen
Doppelklick auf diese Menü-Ressource aus. Im Editorfenster wird dann das vom
Anwendungs-Assistenten erstellte Menü dargestellt:

Dies ist das Standard-Menü, das bisher (fast) jedes im Kurs erstellte MFC-Fenster
besessen hat. Erweitern wir jetzt das vorgegebene Menü. Unser Beispiel soll
nachher an der Position im Fenster, die Sie mit der linken Maustaste anklicken,
entweder eine Linie, einen Kreis oder ein Rechteck zeichnen. Die Auswahl des
darzustellenden Objektes soll über ein Popup-Menü erfolgen. Klicken Sie zur
Erstellung eines neuen Popup-Menüs den im Menü rechts dargestellten leeren Rahmen
an. Der Rahmen erhält darauf eine Markierung. Ziehen Sie den markierten Rahmen
nun mit gedrückter linker Maustaste zwischen die Popup-Menüs Bearbeiten
und ?. Anschließend führen Sie einen Doppelklick auf den eingefügten,
markierten Rahmen aus, worauf folgender Dialog eingeblendet wird:

Hier geben Sie nun im Feld Titel den Text &Objekte ein.
Dies ist die Überschrift unseres neuen Popup-Menüs. Die restlichen Einstellung
lassen Sie unverändert. Drücken Sie die RETURN-Taste und dem Menü wird das soeben
neu erstellte Popup-Menü hinzugefügt. Der Buchstabe, der dem Zeichen &
folgt, wird unterstrichen ausgegeben und kann als Shortcut für den Zugriff auf
das Popup-Menü verwendet werden. In unserem Fall erreichen Sie später das Popup-Menü
Objekte also durch drücken der Tasten <ALT>-<O>.

Gleichzeitig wurde durch den Menü-Editor dem Popup-Menü ein leerer Menüeintrag
hinzugefügt (markierter Rahmen im Bild oben). Wir fügen dem Popup-Menü als nächstes
den Menüeintrag hinzu, der für die Auswahl zum Zeichnen einer Linie dienen soll.
Führen Sie dazu einen Doppelklick auf den markierten Rahmen aus und es wird
wieder der gleiche Dialog wie vorhin eingeblendet, mit zwei wesentlichen Unterschieden:
der Eintrag ID im Dialog ist nun nicht mehr gesperrt ist und die Auswahl
Popup ist nicht mehr markiert:

Jeder Menüeintrag wird durch eine ID eindeutig gekennzeichnet, die Sie im
Feld ID angeben müssen. Wir verwenden für die Auswahl einer Linie die
ID ID_LINE und beschriften den Menüeintrag mit &Linie. Die restlichen
Elemente lassen wir unverändert und drücken die RETURN-Taste. Dem Popup-Menü
wurde damit der Menüeintrag Linie hinzugefügt. Wenn später in der Anwendung
dieser Menüeintrag ausgewählt wird, erhält die Anwendung eine Nachricht mit
der angegebenen ID, hier also ID_LINE. Wie diese Nachricht verarbeitet wird,
das erfahren Sie etwas später.
Als nächstes wollen wir dem Popup-Menü eine Trennlinie hinzufügen. Führen
Sie dazu wieder einen Doppelklick auf den markierten Rahmen aus und es wird
der der bekannte Dialog erneut eingeblendet. Markieren Sie nun die Auswahl
Trennlinie im Dialog und drücken dann die RETURN-Taste. Ihr Popup-Menü
hat soeben eine Trennlinie erhalten. Ganz einfach, oder? Vervollständigen Sie
das Popup-Menü jetzt bis es folgendes Aussehen besitzt:

Fügen Sie anschließend dem Menü ein weiteres Popup-Menü mit den folgenden
Menüeinträgen hinzu:

Übersetzen und starten Sie das Beispiel.
|
 |
Menü-IDs beginnen in der Regel alle mit dem Präfix ID_xxx.
Und noch etwas Wichtiges. Vielleicht ist Ihnen schon einmal aufgefallen,
dass einige Menüeinträge mit '...' aufhören (siehe z.B. im Popup-Menü
Datei die Einträge Öffnen... und Speichern unter...).
Menüeinträge die mit '...' enden führen keine unmittelbaren Aktionen
aus, sondern sie blenden immer einen zusätzlichen Dialog ein. An diese Konvention
sollten Sie sich halten, sie ist sozusagen ungeschriebenes Gesetz!
|
Wenn Sie eines der hinzugefügten Popup-Menüs einmal anklicken werden Sie feststellen,
dass die Menüeinträge alle gesperrt sind. Das Rahmenprogramm der MFC sperrt automatisch
alle Menüeinträge für die keine entsprechenden Nachrichtenbearbeiter definiert sind.
Fügen wir als nächstes die Nachrichtenbearbeiter für die Menüeinträge hinzu.
Nachrichtenbearbeiter für Menüeinträge können an mehreren Stellen definiert werden:
in der Klasse des Rahmenfensters, in der Ansichtsklasse, in der Dokumentenklasse
oder auch in der Anwendungsklasse. Das Menü selbst gehört jedoch immer zum Rahmenfenster.
Alle Methoden, die sich mit der Manipulation von Menüs befassen, sind aus
diesem Grunde stets Methoden der Klasse CFrameWnd. Das Rahmenprogramm der
MFC leitet jedoch Menü-Nachrichten, die nicht vom Rahmenfenster bearbeitet werden,
entsprechend weiter. Wo Sie die Nachrichten der Menüeinträge letztendlich verarbeiten
hängt von der Aktion ab, die Sie mit dem Menüeintrag durchführen wollen. Da sich
unsere neu hinzugefügten Menüeinträge direkt mit der Darstellung von entsprechenden
Grafiken innerhalb des Ansichtsobjekts befassen, bietet es sich an, die Nachrichtenbearbeiter
auch innerhalb der Ansichtsklasse zu definieren. Selbstverständlich hätten wir auch
die Nachrichtenbearbeiter z.B. im Rahmenfenster definieren können und dann das Ansichtsobjekt
durch Aufruf von Methoden entsprechend steuern können.
 |
Damit das Ansichtsobjekt immer darüber informiert ist, welche
Grafik gerade aktiv, d.h. ausgewählt ist, werden zunächst folgende privat
Membervariablen in der Klasse CMenuView definiert:
CPoint m_CMousePos;
int m_nLThickness;
COLORREF m_Color;
enum {NOTHING, LINE, CIRCLE, RECT} m_eObject; |
m_CMousePos enthält die Position, an der die Grafik zu zeichnen
ist. Wie am Anfang der Lektion erwähnt, soll diese Position später mit der linken
Maustaste festgelegt werden. m_nLThickness definiert die aktuelle Stiftstärke
mit der die Linie gezeichnet werden soll und m_Color enthält die Farbe
der zu zeichnenden Grafik. m_eObject ist eine enum-Variable, die die
zu zeichnende Grafik bestimmt. Und da es immer eine gute Idee ist, Variablen
zu initialisieren, fügen wir der Ansichtsklasse noch die Methode OnInitialUpdate(...)
hinzu und initialisieren dort die Membervariablen entsprechend:
void CMenuView::OnInitialUpdate()
{
CView::OnInitialUpdate();
// TODO: Speziellen Code hier einfügen und/oder Basisklasse aufrufen
// Membervariablen
initialisieren
m_eObject = NOTHING;
m_Color = RGB(255,0,0);
m_nLThickness = 1;
} |
Nach dem Starten des Programms ist zunächst keine Grafik aktiv, die aktuelle
Zeichenfarbe wird auf rot und die Linienstärke auf 1 Pixel gesetzt.
So, fügen wir nun die Nachrichtenbearbeiter für die Menüeinträge im Popup-Menü
Objekte hinzu. Öffnen Sie den Klassen-Assistenten (über das Menü
Ansicht im Visual Studio) um folgenden Dialog eingeblendet zu bekommen:

Wie Sie sehen, sind die IDs der neu hinzugefügten Menüeinträge bereits im
Auswahlfeld Objekt-IDs aufgeführt. Da wir die Nachrichtenbearbeiter
für die Menüeinträge in der Klasse CMenuView definieren wollen, wählen
Sie als erstes diese Klasse im Auswahlfeld Klassenname aus. Über diese
Auswahl bestimmen Sie, in welcher Klasse der Nachrichtenbearbeiter definiert
wird. Als nächstes suchen Sie im Auswahlfeld Objekt-IDs die ID ID_LINE
und klicken diese an. Im rechts davon befindlichen Auswahlfeld Nachrichten
werden dann alle Nachrichten anzeigt, die Sie mit der ausgewählten ID verknüpfen
können. Führen Sie einen Doppelklick auf den Eintrag COMMAND im Auswahlfeld
Nachrichten aus. Der Klassen-Assistent öffnet daraufhin einen weiteren
Dialog, in dem Sie den Namen der Methode die mit der Nachricht verknüpft werden
soll eingeben können. Belassen Sie es bei dem Vorschlag OnLine(...)
und klicken Sie den Button OK an. Der Klassen-Assistent erstellt dann
die Methode OnLine(...) und verknüpft sie gleichzeitig (über die Nachrichtentabelle)
mit der Nachricht vom Menüeintrag Linie. Das war's auch schon. So einfach
können Sie mit Hilfe des Klassen-Assistenten Nachrichten von Menüeinträgen mit
Methoden verknüpfen. Führen Sie die gleich Aktion für die restlichen Menüeinträge
ID_CIRCLE, ID_RECT, ID_RED, ID_BLUE und ID_GREEN durch. Achten Sie aber immer
darauf, das im Auswahlfeld Klassenname auch die Klasse CMenuView
spezifiziert ist!
|
 |
Welche Bedeutung die Nachricht UPDATE_COMMAND_UI im Nachrichtenfeld besitzt
das erfahren Sie später noch. |
Damit hätten wir für alle hinzugefügten Menüeinträge entsprechende Nachrichtenbearbeiter
definiert. Im nächsten Schritt füllen wir die Nachrichtenarbeiter mit Leben.
 |
In den Nachrichtenbearbeiter setzen wir die vorhin definierten
Membervariablen m_Color und m_eObject einfach auf die entsprechenden
Werte.
void CMenuView::OnBlue()
{
// TODO: Code für Befehlsbehandlungsroutine hier einfügen
m_Color = RGB(0,0,255);
}
void CMenuView::OnCircle()
{
// TODO: Code für Befehlsbehandlungsroutine hier einfügen
m_eObject = CIRCLE;
}
void CMenuView::OnGreen()
{
// TODO: Code für Befehlsbehandlungsroutine hier einfügen
m_Color = RGB(0,255,0);
}
void CMenuView::OnLine()
{
// TODO: Code für Befehlsbehandlungsroutine hier einfügen
m_eObject = LINE;
}
void CMenuView::OnRect()
{
// TODO: Code für Befehlsbehandlungsroutine hier einfügen
m_eObject = RECT;
}
void CMenuView::OnRed()
{
// TODO: Code für Befehlsbehandlungsroutine hier einfügen
m_Color = RGB(255,0,0);
} |
|
Und damit sind wir fast fertig. Nur das Zeichnen der Grafik selbst fehlt uns
noch. Die Grafik soll, wie bereits erwähnt, immer an der Position gezeichnet werden,
an der die linke Maustaste gedrückt wurde. Diese Position ist zunächst in der Membervariable
m_CMousePos abzulegen und dann der Fensterinhalt als ungültig zu kennzeichnen.
 |
Fügen Sie der Klasse CMenuView die Methode OnLButtonDown(...)
hinzu. Legen Sie dort die aktuelle Mausposition in der Membervariable m_CMousePos
ab und lassen dann das Fenster neu zeichnen. Zum Schluss ist noch die Methode
OnDraw(...) wie nachfolgend angegeben zu implementieren:
void CMenuView::OnLButtonDown(UINT
nFlags, CPoint point)
{
// TODO: Code für die Behandlungsroutine für Nachrichten hier
einfügen...
m_CMousePos = point;
Invalidate();
}
void CMenuView::OnDraw(CDC* pDC)
{
CMenuDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// ZU ERLEDIGEN: Hier Code zum Zeichnen der ursprünglichen Daten
hinzufügen
switch (m_eObject)
{
case LINE:
{
CPen CLinePen(PS_SOLID,m_nLThickness,m_Color);
CPen *pCOldPen
= pDC->SelectObject(&CLinePen);
pDC->MoveTo(m_CMousePos.x-20,m_CMousePos.y-20);
pDC->LineTo(m_CMousePos.x+20,m_CMousePos.y+20);
pDC->SelectObject(pCOldPen);
}
break;
case CIRCLE:
{
CPen CFramePen(PS_SOLID,m_nLThickness,(~m_Color)&0x00FFFFFFUL);
CPen *pCOldPen
= pDC->SelectObject(&CFramePen);
CBrush CFillBrush(m_Color);
CBrush *pCOldBrush
= pDC->SelectObject(&CFillBrush);
pDC->Ellipse(m_CMousePos.x-20,m_CMousePos.y-20,
m_CMousePos.x+20,m_CMousePos.y+20);
pDC->SelectObject(pCOldBrush);
pDC->SelectObject(pCOldPen);
}
break;
case RECT:
{
CPen CFramePen(PS_SOLID,m_nLThickness,(~m_Color)&0x00FFFFFFUL);
CPen *pCOldPen
= pDC->SelectObject(&CFramePen);
CBrush CFillBrush(m_Color);
CBrush *pCOldBrush
= pDC->SelectObject(&CFillBrush);
pDC->Rectangle(m_CMousePos.x-20,m_CMousePos.y-20,
m_CMousePos.x+20,m_CMousePos.y+20);
pDC->SelectObject(pCOldBrush);
pDC->SelectObject(pCOldPen);
}
break;
}
} |
Übersetzen und starten Sie das Programm. Wenn Sie jetzt die linke Maustaste
drücken wird eine entsprechende Grafik in der ausgewählten Farbe dargestellt.
|
Im Prinzip könnten wir damit diese Lektion beenden. Sie wissen nun, wie man Popup-Menüs
mit Menüeinträgen erstellt und die Menüeinträge mit entsprechenden Nachrichtenbearbeitern
verknüpft. Wir werden nun aber noch etwas mit den Menüs experimentieren. Vielleicht
ist Ihnen schon aufgefallen, dass in manchen Anwendungen die zuletzt ausgewählten
Menüeinträge mit einem kleinen Haken, dem so genannten Checkmark, versehen sind.
Und genau diese Eigenschaft werden wir jetzt dem Farbe-Menü hinzufügen. Um für einen
Menüeintrag ein Checkmark zu setzen oder zu löschen, wird die CMenu Methode
CheckMenuItem(...) aufgerufen. Der erste Parameter der Methode spezifiziert,
welcher Menüeintrag beeinflusst werden soll. Hier kann entweder die Position innerhalb
des Popup-Menüs angeben werden oder aber die entsprechende ID, je nach dem welches
Flag im zweiten Parameter gesetzt ist. Der zweite Parameter gibt an, ob ein Checkmark
gesetzt oder gelöscht werden soll und wie der erste Parameter zu interpretieren
ist. Für diesen Parameter sind folgenden Werte zugelassen:
|
Wert
|
Bedeutung
|
| MF_BYPOSITION |
Der erste Parameter enthält
die Position des zu verändernden Menüeintrags, wobei der erste Menüeintrag die
Position 0 besitzt. |
| MF_BYCOMMAND |
Der erste Parameter enthält
die ID des zu verändernden Menüeintrags. |
| MF_CHECKED |
Setzt das Checkmark. |
| MF_UNCHECKED |
Löscht das Checkmark. |
Eigentlich doch ganz einfach? Doch das Problem das sich dabei nun stellt ist
folgendes: wie erhält man ein CMenu-Objekt zu einem bestehenden Popup-Menü?
Die Methode CheckMenuItem(...) ist ja eine Methode der Klasse CMenu.
Hierbei muss in der Regel zweistufig vorgegangen werden. Als erstes müssen Sie das
CMenü Objekt des Menüs (das ist der Menübalken!) ermitteln. Rufen Sie dazu
die CWnd Methode GetMenu(...) des Rahmenfensters auf. Sie liefert
als Returnwert einen Zeiger auf das CMenu-Objekt des Fensters. Danach kann
durch den Aufruf der CMenu Methode GetSubMenu(...) des Menüs der
CMenu-Zeiger auf das gewünschte Popup-Menü ermittelt werden. Die Methode
erhält als Parameter die Position des Popup-Menüs, für das das CMenu-Objekt
geliefert werden soll. Beachten Sie dabei bitte, dass das erste Popup-Menü (in der
Regel das Popup-Menü Datei) die Position '0' besitzt. Über diesen CMenu-Zeiger
auf das Popup-Menü können Sie nun die oben aufgeführte CheckMenuItem(...)
Methode aufrufen, um z.B. einen Menüeintrag mit einem Checkmark zu versehen.
 |
Beide Methoden GetMenu(...) wie auch GetSubMenu(...) liefern
Zeiger auf temporäre CMenu-Objekte zurück. Diese Zeiger sind nur solange
gültig, bis die Bearbeitung der aktuellen Nachricht abgeschlossen ist! |
 |
So, uns jetzt sind Sie endlich mal wieder dran. Versehen Sie
jetzt den Menüeintrag im Popup-Menü Farbe mit einem Checkmark, dessen
Einstellung gerade gültig ist. Denken Sie auch daran, den aktuellen Menüeintrag
beim Starten des Programms mit einem Checkmark zu versehen!
 |
Na, genug geschwitzt? Dann kann ich Ihnen auch meine Lösung anzeigen. |
Lösung zur Ausgabe von Checkmarks
Als erstes müssen Sie in der Methode OnInitialUpdate(...)
für die Farbe rot das Checkmark setzen.
void CMenuView::OnInitialUpdate()
{
....
m_nLThickness = 1;
// ausgewaehlte
Farbe mit Checkmark versehen
// CMenu-Zeiger auf Menue (Fenstermenue) holen
CMenu *pMenuBar = GetParent()->GetMenu();
// CMenu-Zeiger auf
Popup-Menue 'Farbe' holen,
// ist 4. Popup-Menue im Fenstermenue
CMenu *pColorMenu =
pMenuBar->GetSubMenu(3);
// Menue-Eintrag ID_RED
mit Checkmark versehen
pColorMenu->CheckMenuItem(ID_RED,MF_CHECKED);
} |
Anschließend können dann die Nachrichtenbearbeiter für die Farbauswahl
wie folgt erweitert werden:
void CMenuView::OnBlue()
{
// TODO: Code für Befehlsbehandlungsroutine hier einfügen
m_Color = RGB(0,0,255);
// Checkmarks setzen
CMenu *pMenuBar = GetParent()->GetMenu();
CMenu *pColorMenu = pMenuBar->GetSubMenu(3);
pColorMenu->CheckMenuItem(ID_BLUE,MF_CHECKED);
pColorMenu->CheckMenuItem(ID_GREEN,MF_UNCHECKED);
pColorMenu->CheckMenuItem(ID_RED,MF_UNCHECKED);
}
void CMenuView::OnGreen()
{
// TODO: Code für Befehlsbehandlungsroutine hier einfügen
m_Color = RGB(0,255,0);
// Checkmarks setzen
CMenu *pMenuBar = GetParent()->GetMenu();
CMenu *pColorMenu = pMenuBar->GetSubMenu(3);
pColorMenu->CheckMenuItem(ID_BLUE,MF_UNCHECKED);
pColorMenu->CheckMenuItem(ID_GREEN,MF_CHECKED);
pColorMenu->CheckMenuItem(ID_RED,MF_UNCHECKED);
}
void CMenuView::OnRed()
{
// TODO: Code für Befehlsbehandlungsroutine hier einfügen
m_Color = RGB(255,0,0);
// Checkmarks setzen
CMenu *pMenuBar = GetParent()->GetMenu();
CMenu *pColorMenu = pMenuBar->GetSubMenu(3);
pColorMenu->CheckMenuItem(ID_BLUE,MF_UNCHECKED);
pColorMenu->CheckMenuItem(ID_GREEN,MF_UNCHECKED);
pColorMenu->CheckMenuItem(ID_RED,MF_CHECKED);
} |
Sie sehen, relativ viel Aufwand für eine 'nette' Kleinigkeit. Aber so
ist halt das Leben. Haben Sie auch nicht vergessen, das vorherige Checkmark
auch wieder wegzunehmen?
Ende der Lösung
|
Wenn Sie das Programm übersetzen und starten, wird die aktuelle Farbauswahl
im Popup-Menü Farbe mit einem Checkmark versehen werden.
|
Aber gehen wir noch einen Schritt weiter. Wenn Sie sich das Menü im Visual Studio
einmal genauer angesehen haben, werden Sie vielleicht bemerken, dass je nach Aktion
manchmal zusätzliche Popup-Menüs eingeblendet werden. Wie Sie so etwas auch erreichen
können, das erfahren Sie jetzt.
Im Beispiel soll die Linienstärke des Linienobjektes über ein zusätzliches Popup-Menü
eingestellt werden können. Dieses Popup-Menü soll aber auch nur dann erscheinen,
wenn das aktuelle Objekt auch ein Linienobjekt ist. Dazu muss zuerst für das wahlweise
einzublendende Popup-Menü ein gesondertes Menü erstellt werden.
 |
Gehen Sie nun wieder in die Ressourcen-Ansicht, klicken dort
den Ressource-Typ Menu mit der rechten Maustaste an und wählen im eingeblendeten
Kontext-Menü den Eintrag Menü einfügen aus. Daraufhin wird ein neues
Menü mit der ID IDR_MENU1 erstellt das einen noch leeren Menübar besitzt. Klicken
Sie jetzt mit der rechten Maustaste ins Editorfenster des Menü-Editors und wählen
Sie aus dem dann eingeblendeten Kontext-Menü den Eintrag Als Kontextmenü
anzeigen aus. Legen Sie danach ein Menü mit den unten angegebenen Menüeinträgen
und den entsprechenden IDs an:

Zum Schluss ändern Sie noch die ID des Menüs von IDR_MENU1 auf
IDR_LTHICKNESS
|
Da dieses Menü nicht automatisch, wie das Fenstermenü, durch das Rahmenprogramm
geladen wird, muss dies explizit erfolgen. Das Laden erfolgt durch den Aufruf der
CMenu Methode LoadMenu(...). Nach dem Laden des Menüs kann das
Popup-Menü dann bei Bedarf in das bestehende Menü eingefügt werden. Hierfür besitzt
die Klasse CMenu die Methode InsertMenu(...), mit deren Hilfe
einem bestehenden Menü weitere Popup-Menüs hinzugefügt werden können oder aber auch
einem Popup-Menü neue Menüeinträge. Die Methode erhält u.a. als Parameter die Position
im Menü, vor der das neue Popup-Menü bzw. der neue Menüeintrag eingefügt
werden soll. Beachten Sie bitte bei der Angabe des Menütextes, dass das Zeichen
'&' dazu verwendet wird die Auswahltaste zu bestimmen.
Um ein Popup-Menü oder einen Menüeintrag zu entfernen dient die CMenu
Methode RemoveMenu(...).
Das solchermaßen modifizierte Menü wird aber nicht automatisch neu dargestellt
sondern erst durch den Aufruf der CMenu Methode DrawMenuBar(...).
Bauen wir jetzt das zusätzliche Popup-Menü in unser Beispiel ein.
 |
Nachdem im vorherigen Schritt das neue Popup-Menü erstellt
wurde, laden wir dieses Menü in der Methode OnInitialUpdate(...). Fügen
Sie dazu der Klasse CMenuView zunächst die Membervariable m_CLineMenu
vom Typ CMenu hinzu. Anschließend erweitern Sie die Methode OnInitialUpdate(...)
wie folgt:
void CMenuView::OnInitialUpdate()
{
CView::OnInitialUpdate();
// TODO: Speziellen Code hier einfügen und/oder Basisklasse aufrufen
....
// Menue-Eintrag ID_RED mit Checkmark versehen
pColorMenu->CheckMenuItem(ID_RED,MF_CHECKED);
// Popup-Menue fuer
Linienstaerke laden
// wird noch nicht dargestellt!
m_CLineMenu.LoadMenu(IDR_LTHICKNESS);
} |
Anschließend sind die Methoden OnLine(...), OnCircle(...) und
OnRect(...) noch wie folgt anzupassen:
void CMenuView::OnLine()
{
// TODO: Code für Befehlsbehandlungsroutine hier einfügen
// Falls Linienobjekt
noch nicht aktiv ist
if (m_eObject != LINE)
{
// Linienobjekt aktivieren
m_eObject = LINE;
// Popup-Menue fuer Linienstaerke hinzufuegen
CMenu *pMenuBar = GetParent()->GetMenu();
pMenuBar->InsertMenu(4,MF_BYPOSITION|MF_POPUP,
(UINT)m_CLineMenu.m_hMenu,"&LStärke");
GetParent()->DrawMenuBar();
}
}
void CMenuView::OnCircle()
{
// TODO: Code für Befehlsbehandlungsroutine hier einfügen
// Falls Linienobjekt
aktiv war
if (m_eObject == LINE)
{
// Popup-Menu fuer Linienstaerke entfernen
CMenu *pMenuBar = GetParent()->GetMenu();
pMenuBar->RemoveMenu(4,MF_BYPOSITION);
GetParent()->DrawMenuBar();
}
m_eObject = CIRCLE;
}
void CMenuView::OnRect()
{
// TODO: Code für Befehlsbehandlungsroutine hier einfügen
// Falls Linienobjekt
aktiv war
if (m_eObject == LINE)
{
// Popup-Menu fuer Linienstaerke entfernen
CMenu *pMenuBar = GetParent()->GetMenu();
pMenuBar->RemoveMenu(4,MF_BYPOSITION);
GetParent()->DrawMenuBar();
}
m_eObject = RECT;
} |
Damit sind wir fast fertig. Was jetzt nur noch fehlt, sind die entsprechenden
Nachrichtenbearbeiter für die neuen Menüeinträge. Fügen Sie, wie am Anfang der
Lektion beschrieben, die Nachrichtenbearbeiter über den Klassen-Assistenten
hinzu und erweitern Sie die neuen Methoden wie nachfolgenden angegeben:
void CMenuView::On1pix()
{
// TODO: Code für Befehlsbehandlungsroutine hier einfügen
m_nLThickness = 1;
}
void CMenuView::On2pix()
{
// TODO: Code für Befehlsbehandlungsroutine hier einfügen
m_nLThickness = 2;
}
void CMenuView::On4pix()
{
// TODO: Code für Befehlsbehandlungsroutine hier einfügen
m_nLThickness = 4;
} |
Das war's! Übersetzen und starten Sie das Programm. Wenn das Linienobjekt
aktiv ist wird nun zusätzlich das neu erstellte Popup-Menü zum Menü hinzugefügt
|
Zum Schluss werden wir dem Beispiel noch den 'letzten Schliff' geben. Das Popup-Menü
zum Einstellen der Linienstärke soll nun auch als Kontext-Menü angezeigt werden
wenn die rechte Maustaste gedrückt wird und das Linienobjekt aktiv ist. Zur Darstellung
eines Kontext-Menüs stellt die Klasse CMenu die Methode TrackPopupMenu(...)
bereit. Die Parameter zur Methode entnehmen Sie bitte der Online-Hilfe zur gleichnamigen
API-Funktion. Die Online-Hilfe zur CMenu-Methode ist nicht ganz
auf dem aktuellen Stand. Beachten Sie bitte bei der Angabe der Menüposition beim
Aufruf der Methode, dass diese in Bildschirmkoordinaten angegeben werden muss!
 |
So, nun dürfen Sie wieder üben. Versuchen Sie nun einmal das
vorher angelegt Menü für die Auswahl der Stiftdicke als Kontextmenü darzustellen.
Das CMenu-Objekt für das Kontextmenü ist das vorhin angelegte Objekt
m_CLineMenu. Kontextmenüs werden immer dann eingeblendet, wenn die
rechte Maustaste gedrückt wird. Beachten Sie dabei aber bitte, dass das Kontextmenü
auch nur dann dargestellt werden soll, wenn als aktuelles Objekt das Linienobjekt
eingestellt ist. Sie brauchen für die Lösung der Aufgabe 'nur' eine kleine Methode
zum bisherigen Beispiel hinzuzufügen.
 |
Na, genug geschwitzt? Dann kann ich Ihnen auch meine Lösung anzeigen. |
Lösung zur Ausgabe des Kontextmenüs
Das Kontextmenü wird, wie soll's auch anders sein, innerhalb
der Methode OnRButtonDown(...) dargestellt.
void CMenuView::OnRButtonDown(UINT
nFlags, CPoint point)
{
// TODO: Code für die Behandlungsroutine für Nachrichten hier
einfügen....
// Falls nicht
Linienobjekt aktiv ist, Peep!
if (m_eObject != LINE)
MessageBeep(-1);
else
{
// Client-Koordinaten in Screen-Koordinaten umrechnen
ClientToScreen(&point);
// Kontext-Menue ausgeben
m_CLineMenu.TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON,
point.x,point.y,this,NULL);
}
} |
Das wohl einzige größere Problem bei dieser Übung dürfte wohl die Positionierung
des Kontextmenüs gewesen sein. In der obigen Lösung wir das Kontextmenü
an der Position dargestellt, an der Sie die Maustaste gedrückt haben. Da
die Methode TrackPopupMenu(...) die Position aber in Bildschirmkoordinaten
benötigt, wird die Mauskoordinate (immer relativ zur Client-Area des Fensters)
mittels ClientToScreen(...) entsprechend umgerechnet.
Ende der Lösung
|
Damit ist das Beispiel fertig. Sie finden das komplette Beispiel auch im
Verzeichnis 07Ressourcen\Menu.
|
Bei den Tipps&Tricks zu den Ressourcen können Sie sich u.a. noch ansehen, wie
Menüeinträge mit Icons versehen werden können.
Sehen wir uns zum Schluss noch an, was es mit der Nachrichten UPDATE_COMMAND_UI
auf sich hat. Nun, bevor ein Menü dargestellt wird, ruft das Rahmenprogramm der
MFC für jeden Menüpunkt dessen OnUpdateXxxx(...) Methode auf. Sie haben
in dieser Methode dann u.a. die Möglichkeit, Menüpunkte explizit zu sperren. Wie
so etwas vonstatten geht, können Sie sich im folgenden Listing noch ansehen:
 |
Im Beispiel wollen wir die erneute Auswahl der Farbe blau nur
dann zulassen, wenn das Linienobjekt aktiv ist. Dazu ist für die ID ID_BLUE
der Nachrichtenbearbeiter UPDATE_COMMAND_UI mit Hilfe des Klassen-Assistenten
zu erstellen. Modifizieren Sie die Methode wie folgt:
void CMenuView::OnUpdateBlue(CCmdUI*
pCmdUI)
{
// TODO: Code für die Befehlsbehandlungsroutine zum Aktualisieren
....
pCmdUI->Enable(m_eObject==LINE);
} |
Der Menüeintrag wird jetzt nur noch dann freigegeben, wenn das Linienobjekt
aktiv ist.
|
So, in der nächsten Lektion geht's dann weiter mit der nächsten Ressource, den
Schnellzugriffstasten.
|