Click to open or copy the DYNAMENU project files.
DYNAMENU illustrates dynamic modification of menus and status bars regardless of whether handling commands are known at compile time. DYNAMENU illustrates the following capabilities:
DYNAMENU initially displays a window with the text: "This text is displayed in the current color." You can change the color of the displayed text by selecting one of four items initially offered in the Color menu: Black, Red, Purple, or Blue.
To exercise the dynamic menu updating feature of DYNAMENU, click Change Options on the Color menu, which opens a Change Color Options dialog box. Four check boxes for Black, Red, Purple and Blue allow you to choose which colors are dynamically offered in the Color menu. For example, if you clear (uncheck) Red and Purple and return to the Color menu, only Black and Blue items will be offered in the menu.
Notice how the status bar displays, for example, "Set current color text to Black," when the focus is on the Black item in the Color menu.
Class CDynaMDIChildWnd in Mdichild.cpp implements dynamic updating of items in the Color menu. When the list of available colors is updated, or when then MDI child window is activated, the CDynaMDIChildWnd::RefreshColorMenu function calls CMenu::DeleteMenu to delete each color item from the menu, and then adds the currently available colors to the menu using CMenu::AppendMenu.
Implementing Command Handlers for Dynamic Menu Items
DYNAMENU could have been implemented by reserving a fixed list of command IDs for the colors: ID_COLOR_BLACK, ID_COLOR_RED, etc. In such a case, ON_COMMAND and ON_UPDATE_COMMAND_UI handlers could have been implemented for the color commands as usual. This would be the most straightforward way to implement DYNAMENU.
However, for sake of illustration, DYNAMENU does not use fixed command IDs. Instead, DYNAMENU dynamically assigns command IDs not known or associated with the menu items at compile time. This illustration can be applied to more complex cases, such as user-configurable menus.
The equivalent of ON_COMMAND and ON_UPDATE_COMMAND message map handling is implemented in the document's override of CCmdTarget::OnCmdMsg. If the OnCmdMsg function is called with a NULL pointer for the AFX_CMDHANDLERINFO* parameter, this means that no message map entry has been found for the command. In this case, the override of OnCmdMsg checks whether the command ID, passed as the first parameter, is one of the dynamically assigned command IDs for the color menu items. If so, the override calls either a command handler (DoSelectColor) or command user interface handler (DoUpdateSelectColor), depending on whether the second parameter passed to OnCmdMsg is the MFC-defined CN_COMMAND or CN_UPDATE_COMMAND_UI.
In DYNAMENU, the MDI child window (CDynaMDIChildWnd) owns the status bar. The default implementation of CFrameWnd::GetMessageString uses the currently shown command ID (for the item that currently has the focus in the menu) to get the corresponding string resource for the command and display it in the first pane of the status bar. DYNAMENU overrides GetMessageString to display a command prompt for the dynamically defined commands.
This sample demonstrates the following keywords:
AfxFormatString1; AfxGetMainWnd; CCmdTarget::OnCmdMsg; CDialog::DoModal; CDialog::OnInitDialog; CDocument::GetFirstViewPosition; CDocument::GetNextView; CDocument::OnNewDocument; CDocument::UpdateAllViews; CFrameWnd::Create; CFrameWnd::GetActiveDocument; CFrameWnd::GetMessageString; CFrameWnd::LoadFrame; CMenu::AppendMenu; CMenu::DeleteMenu; CMenu::GetMenuItemCount; CMenu::GetMenuItemID; CMenu::GetSubMenu; CObject::AssertValid; CObject::Dump; CObject::Serialize; CString::LoadString; CView::DoPreparePrinting; CView::GetDocument; CView::OnBeginPrinting; CView::OnDraw; CView::OnEndPrinting; CView::OnPreparePrinting; CWinApp::AddDocTemplate; CWinApp::EnableShellOpen; CWinApp::InitInstance; CWinApp::LoadStdProfileSettings; CWinApp::RegisterShellFileTypes; CWinApp::SetDialogBkColor; CWnd::CenterWindow; CWnd::DoDataExchange; CWnd::GetClientRect; CWnd::GetDlgItem; CWnd::GetMenu; CWnd::GetParentFrame; CWnd::OnCreate; CWnd::SetWindowText; CWnd::ShowWindow; CWnd::UpdateWindow; DragAcceptFiles; DrawText; LoadBitmap; RGB; SetBkMode; SetTextColor