Advanced MFC Programming

Advanced MFC Programming Advanced MFC Programming

math.hcmuns.edu.vn
from math.hcmuns.edu.vn More from this publisher
11.04.2014 Views

Chapter 2. Menu in class CMenuDoc, whose function names are OnEditInsertDynamicMenu, OnUpdateEditInsertDynamicMenu, OnEditDeleteDynamicMenu and OnUpdateEditDeleteDynamicMenu. Because we want to disable command ID_EDIT_DELETEDYNAMICMENU and enable command ID_EDIT_INSERTDYNAMICMENU before the sub-menu is inserted, and reverse this after the menu is inserted, another Boolean type variable m_bSubMenuOn is declared in class CMenuDoc, which will be used to indicate the state of the inserted menu. It is initialized to FALSE in the constructor. Preparing the menu resource that will be used to implement dynamic sub-menu is the same with what we did in the previous sample. Here a resource IDR_MENU_POPUP is added to the application, whose content is the same with the resource created in sample 2.2\Menu. In this case, we could not use a local variable to load the menu, because once the menu is inserted, it may exist for a while before the user removes it. If we still use a local variable, it will go out of scope after the messagae hander returns. In the sample, a CMenu type variable is declared in class CMenuDoc, which is used to load the menu resource in the constructor. The following shows the modified class CMenuDoc: …… class CMenuDoc : public CDocument { protected: // create from serialization only CMenu m_menuSub; BOOL m_bSubMenuOn; protected: //{{AFX_MSG(CMenuDoc) afx_msg void OnEditInsertDynamicMenu(); afx_msg void OnUpdateEditInsertDynamicMenu(CCmdUI* pCmdUI); afx_msg void OnEditDeleteDynamicMenu(); afx_msg void OnUpdateEditDeleteDynamicMenu(CCmdUI* pCmdUI); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; The following is the constructor within which the menu resource is loaded and m_bSubMenuOn is initialized: CMenuDoc::CMenuDoc() { m_menuSub.LoadMenu(IDR_MENU_POPUP); m_bSubMenuOn=FALSE; } The following shows two UPDATE_COMMAND_UI message handlers where two menu commands are enabled or disabled: void CMenuDoc::OnUpdateEditInsertDynamicMenu(CCmdUI* pCmdUI) { pCmdUI->Enable(m_bSubMenuOn == FALSE); } void CMenuDoc::OnUpdateEditDeleteDynamicMenu(CCmdUI* pCmdUI) { pCmdUI->Enable(m_bSubMenuOn == TRUE); } At last, we must implement two WM_COMMAND message handlers. First, we need to find a way of accessing mainframe menu IDR_MAINFRAME of the application. In MFC, a menu associated with a window can be accessed by calling function CWnd::GetMenu(), which will return a CMenu type pointer. Once we get this pointer, we can use it to access any of its sub-menus. The mainframe window pointer can be obtained by calling function AfxGetMainWnd() anywhere in the program. An alternate way is to call AfxGetApp() to obtain a CWinApp type pointer, then access its public member m_pMainWnd. We could use CMenu type pointer to insert or remove a sub-menu dynamically. The following shows two message handlers that are used to insert or remove the sub-menu: 44

Chapter 2. Menu void CMenuDoc::OnEditInsertDynamicMenu() { CMenu *pTopMenu=AfxGetMainWnd()->GetMenu(); CMenu *ptrMenu=m_menuSub.GetSubMenu(0); pTopMenu->InsertMenu ( 1, MF_BYPOSITION | MF_POPUP, (UINT)ptrMenu->GetSafeHmenu(), "&Dynamic Menu" ); AfxGetMainWnd()->DrawMenuBar(); m_bSubMenuOn=TRUE; } void CMenuDoc::OnEditDeleteDynamicMenu() { CMenu *pTopMenu=AfxGetMainWnd()->GetMenu(); pTopMenu->RemoveMenu(1, MF_BYPOSITION); AfxGetMainWnd()->DrawMenuBar(); m_bSubMenuOn=FALSE; } When inserting sub-menu, flag MF_BYPOSITION is used. This is because the first level menu items do not have command IDs. After the menu is inserted or removed, we must call function CWnd::DrawMenuBar() to let the menu be updated. Otherwise although the content of the menu is actually changed, it will not be reflected to the user interface until the update is triggered by some other reasons. 2.4 Bitmap Check The default menu check provided by MFC is a tick mark, and nothing is displayed when the check is removed. With a little effort, we can prepare our own bitmaps and use them to implement the checked and unchecked state (Figure 2-3). To implement the checked and unchecked states of menu items using bitmaps, we need to call the following member function of CMenu: BOOL CMenu::SetMenuItemBitmaps ( UINT nPosition, UINT nFlags, const CBitmap* pBmpUnchecked, const CBitmap* pBmpChecked ); The first two parameters of this function indicate which menu item we are working with. Their meanings are the same with that of functions such as CMenu::EnableMenuItem(…). When calling this function, we can use either a command ID or an absolute position to identify a menu item. The third and fourth parameters are pointers to bitmaps (CBitmap type objects), one for checked state, one for unchecked state. Bitmap checks Standard checks Figure 2-3. Standard menu checks and bitmap menu checks Like menu, bitmap can also be prepared as resource then be loaded at program’s runtime. We can edit a bitmap in Developer Studio, and save it as application’s resource. Adding a bitmap resource is the same 45

Chapter 2. Menu<br />

in class CMenuDoc, whose function names are OnEditInsertDynamicMenu,<br />

OnUpdateEditInsertDynamicMenu, OnEditDeleteDynamicMenu and OnUpdateEditDeleteDynamicMenu.<br />

Because we want to disable command ID_EDIT_DELETEDYNAMICMENU and enable command<br />

ID_EDIT_INSERTDYNAMICMENU before the sub-menu is inserted, and reverse this after the menu is inserted,<br />

another Boolean type variable m_bSubMenuOn is declared in class CMenuDoc, which will be used to indicate<br />

the state of the inserted menu. It is initialized to FALSE in the constructor.<br />

Preparing the menu resource that will be used to implement dynamic sub-menu is the same with what<br />

we did in the previous sample. Here a resource IDR_MENU_POPUP is added to the application, whose content<br />

is the same with the resource created in sample 2.2\Menu.<br />

In this case, we could not use a local variable to load the menu, because once the menu is inserted, it<br />

may exist for a while before the user removes it. If we still use a local variable, it will go out of scope after<br />

the messagae hander returns. In the sample, a CMenu type variable is declared in class CMenuDoc, which is<br />

used to load the menu resource in the constructor.<br />

The following shows the modified class CMenuDoc:<br />

……<br />

class CMenuDoc : public CDocument<br />

{<br />

protected: // create from serialization only<br />

CMenu m_menuSub;<br />

BOOL m_bSubMenuOn;<br />

protected:<br />

//{{AFX_MSG(CMenuDoc)<br />

afx_msg void OnEditInsertDynamicMenu();<br />

afx_msg void OnUpdateEditInsertDynamicMenu(CCmdUI* pCmdUI);<br />

afx_msg void OnEditDeleteDynamicMenu();<br />

afx_msg void OnUpdateEditDeleteDynamicMenu(CCmdUI* pCmdUI);<br />

//}}AFX_MSG<br />

DECLARE_MESSAGE_MAP()<br />

};<br />

The following is the constructor within which the menu resource is loaded and m_bSubMenuOn is<br />

initialized:<br />

CMenuDoc::CMenuDoc()<br />

{<br />

m_menuSub.LoadMenu(IDR_MENU_POPUP);<br />

m_bSubMenuOn=FALSE;<br />

}<br />

The following shows two UPDATE_COMMAND_UI message handlers where two menu commands are<br />

enabled or disabled:<br />

void CMenuDoc::OnUpdateEditInsertDynamicMenu(CCmdUI* pCmdUI)<br />

{<br />

pCmdUI->Enable(m_bSubMenuOn == FALSE);<br />

}<br />

void CMenuDoc::OnUpdateEditDeleteDynamicMenu(CCmdUI* pCmdUI)<br />

{<br />

pCmdUI->Enable(m_bSubMenuOn == TRUE);<br />

}<br />

At last, we must implement two WM_COMMAND message handlers. First, we need to find a way of<br />

accessing mainframe menu IDR_MAINFRAME of the application. In <strong>MFC</strong>, a menu associated with a window<br />

can be accessed by calling function CWnd::GetMenu(), which will return a CMenu type pointer. Once we get<br />

this pointer, we can use it to access any of its sub-menus.<br />

The mainframe window pointer can be obtained by calling function AfxGetMainWnd() anywhere in the<br />

program. An alternate way is to call AfxGetApp() to obtain a CWinApp type pointer, then access its public<br />

member m_pMainWnd. We could use CMenu type pointer to insert or remove a sub-menu dynamically.<br />

The following shows two message handlers that are used to insert or remove the sub-menu:<br />

44

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!