Advanced MFC Programming
Advanced MFC Programming Advanced MFC Programming
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
- Page 9 and 10: 9.1 Outputting Text Using Different
- Page 11 and 12: Summary SAMPLE: SIMPLE PAINT 11.0 P
- Page 13 and 14: 13.2 Creating Applications without
- Page 15 and 16: Functions Implementing Comparisons
- Page 17 and 18: Chapter 1. Tool Bar and Dialog Bar
- Page 19 and 20: Chapter 1. Tool Bar and Dialog Bar
- Page 21 and 22: Chapter 1. Tool Bar and Dialog Bar
- Page 23 and 24: Chapter 1. Tool Bar and Dialog Bar
- Page 25 and 26: Chapter 1. Tool Bar and Dialog Bar
- Page 27 and 28: Chapter 1. Tool Bar and Dialog Bar
- Page 29 and 30: Chapter 1. Tool Bar and Dialog Bar
- Page 31 and 32: Chapter 1. Tool Bar and Dialog Bar
- Page 33 and 34: Chapter 1. Tool Bar and Dialog Bar
- Page 35 and 36: Chapter 1. Tool Bar and Dialog Bar
- Page 37 and 38: Chapter 1. Tool Bar and Dialog Bar
- Page 39 and 40: Chapter 1. Tool Bar and Dialog Bar
- Page 41 and 42: Chapter 1. Tool Bar and Dialog Bar
- Page 43 and 44: Chapter 1. Tool Bar and Dialog Bar
- Page 45 and 46: Chapter 1. Tool Bar and Dialog Bar
- Page 47 and 48: Chapter 1. Tool Bar and Dialog Bar
- Page 49 and 50: Chapter 2. Menu Chapter 2 Menu Menu
- Page 51 and 52: Chapter 2. Menu ON_COMMAND(ID_EDIT_
- Page 53 and 54: Chapter 2. Menu “clipboard”. We
- Page 55 and 56: Chapter 2. Menu Using Class CMenu W
- Page 57 and 58: Chapter 2. Menu } After implementin
- Page 59: Chapter 2. Menu ); UINT nPosition,
- Page 63 and 64: Chapter 2. Menu } In the sample, bi
- Page 65 and 66: Chapter 2. Menu Message Mapping for
- Page 67 and 68: Chapter 2. Menu We can implement bi
- Page 69 and 70: Chapter 2. Menu CDC *ptrDC; CDC dcM
- Page 71 and 72: Chapter 2. Menu Because the popup m
- Page 73 and 74: Chapter 3. Splitter Window Chapter
- Page 75 and 76: Chapter 3. Splitter Window function
- Page 77 and 78: Chapter 3. Splitter Window BOOL CSp
- Page 79 and 80: Chapter 3. Splitter Window In the a
- Page 81 and 82: Chapter 3. Splitter Window Sample S
- Page 83 and 84: Chapter 3. Splitter Window WM_LBUTT
- Page 85 and 86: Chapter 4. Button Chapter 4 Buttons
- Page 87 and 88: Chapter 4. Button Use string text a
- Page 89 and 90: Chapter 4. Button function, first t
- Page 91 and 92: Chapter 4. Button Now we can remove
- Page 93 and 94: Chapter 4. Button } ( m_bBmpCheck ?
- Page 95 and 96: Chapter 4. Button using bit-wise AN
- Page 97 and 98: Chapter 4. Button Overriding Functi
- Page 99 and 100: Chapter 4. Button …… First pBit
- Page 101 and 102: Chapter 4. Button Using Class MCBit
- Page 103 and 104: Chapter 4. Button The button’s ID
- Page 105 and 106: Chapter 4. Button However, since me
- Page 107 and 108: Chapter 4. Button Here, we use subc
- Page 109 and 110: Chapter 5. Common Controls command
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