📄 06.3.6 mfc菜单命令更新机制.txt
字号:
6.3.6 MFC菜单命令更新机制
利用MFC编程时,菜单项状态的维护依赖于CN_UPDATE_COMMAND_UI消息。我
们可以通过手工,或利用 ClassWizard在消息映射中添加 ON_UPDATE_COMMAND_UI
宏来捕获CN-UPDATE-COMMAND-U消息。
例如,在Menu程序中,如果想让【编辑】子菜单下的【剪切】菜单项变为可以使用的状态,则可以在ClassWizard窗口中,在左边的ObjectIDs列表框中选择ID_EDIT_CUT(这是【剪切】菜单项的标识),在右边的Messages列表框中选择UPDATE_COMMAND_UI消息。选择操作的结果如图6.24所示。
图6.24为剪切菜单项增加UPDATE_C。如1MAND_UI消息处理函数
然后单击【Add Function...】按钮增加一个消息响应函数,再单击【Edit Code】按钮定位到这个新增加的函数定义处。这时, ClassWizard就会在CMainFrame类的消息映射中添加一个 ON_UPDATE_COMMAND_UI宏(这个宏就是用来捕获 CN_UPDATE_ COMMAND UI消息的),我们在该类的源文件中可以看到如例6-14所示代码。
~IJ 6-14
BEG1N_MESSAGE_MAP(CMainFrame , CFrameWnd) 11 {{AFX_MSG_MAP(CMainFrame) ON_WM_CREATE ( ) ON_COMMAND(工DM_TEST, OnTest) ON_UPDATE_COMMAND_U1(工D_ED工T_CUT, OnUpdateEditCut) II}}AFX_MSG_MAP
.
END_MESSAGE_MAP()
当程序框架捕获到了 CN-UPDATE-COMMAND-UI消息后,最终还是交由该消息的响应函数来处理,例如本例中的OnUpdateEditCut函数。如例6-15所示代码是这个函数的初始定义代码。
f9lJ 6-15
void CMainFrame : :OnUpdateEditCut(CCmdU1* pCmdU1) 11 TODO : Add your command update U1 handler code here
我们看到 OnUpdateEditCut这个函数有一个 CCmdUI指针类型的参数。利用这个 CCmdUI类,可以决定一个菜单项是否可以使用、是否有标记,还可以改变菜单项的文本。
飞令·细iR眉 U是UserInterface的简写,就是用户接口。菜单项就是一个用户接口。
国际:四DATE_CO刚AND_UI消息的响应只能应于菜单项,不能应用于
永久显示的顶级菜单(即弹出式菜单)项目。
上例中,我们利用 ClassWizard为【编辑】子菜单下的【剪切】菜单项添加了一个 UPDATE-COMMAND-U消息响应函数, MFC在后台所做的工作是:当要显示菜单时,操作系统发出WM_INITMENUPOPUP消息,然后由程序窗口的基类如CFrameWnd接管。它会创建一个CCmdUI对象,井与程序的第一个菜单项相关联,调用该对象的一个成员函数 DoUpdateO。这个函数发出CN_UPDATE_COMMAND_UI消息,这条消息带有一个指向 CCmdUI对象的指针。这时,系统会判断是否存在一个ON-UPDATE-com4AND-UI宏去捕获这个菜单项消息。如果找到这样一个宏,就调用相应的消息响应函数进行处理,在这个函数中,可以利用传递过来的CCmdUI对象去调用相应的函数,使该菜单项可以使用,或禁用该菜单项。当更新完第一个菜单项后,同一个 CCmdUI对象就设置为与第二个菜单项相关联,依此顺序进行,直到完成所有菜单项的处理。这就是MFC采用的命令更新机制。
4‘ -4-4 I 185
第6
利用 MFC提供的命令更新机制,在程序中实现菜单项的可用或禁用功能时就变得很简单了。我们只需要捕获 UPDATE-COMMAND-U消息,在该消息的响应函数中调用 CCmdUI对象的相应函数,例如Enable, SetCheck或SetText函数,就可以分别实现使菜单项可用或禁用、设置标记菜单,或者设置菜单项的文本这些功能。其中, CCmdUI类的 Enable函数的声明形式如下所示:
virtual void Enable(BOOL bOn = TRUE );
我们注意到,这个函数有一个 BOOL类型的参数,当它的值为TRUE时,使菜单项可用;当其值为FALSE时,禁用菜单项。默认值为TRUE。于是,我们在上述例6-15所示 OnUpdateEditCut函数中添加例6-16中加灰显示的代码,就可以便【剪切1菜单项可用。
例6-16
void CMainFrame : :OnUpdateEditCut(CCmdU1* pCmdU1)
11 TODO : Add your command update U1 handler code here
pCmdU1->Enable() ;
Build并运行Menu程序,打开【编辑】子菜单,就可以发现【剪切】菜单项变成可用状态了,结果如图6.25所示。
同时,我们会发现工具栏上剪切工具按钮也可以使用了。那么工具栏上的按钮与菜单项是如何关联起来的呢?在VC++开发环境中的左边窗格中打开ResourceView选项卡,双击 Toolbar(即工具栏)分支下的工具栏标识: IDR_M E,将会在 VC++开发界面右边的窗口中打开工具栏资源,在【剪切】工具按钮(如图6.26所示)上双击鼠标左键。这时,就会弹出该工具按钮的属性对话框,从而,我们得知它的标识是: ID_EDIT_CUT。
自哑m由旧够哥由手+飞,
图 6.25剪切菜单项变成可用状态图 6.26工具栏资源
然后,我们再看看【剪切】菜单项的标识。方法是用鼠标双击 Menu (即菜单〉分支下的菜单栏标识: IDR MA剧FRAME,将会在VC++开发界面右边的窗口中打开菜单栏资源,单击【编辑】菜单,在打开的菜单项中用鼠标左键双击【剪切】菜单项,即可打开该
'
186 I ~~~
菜单项的属性对话框。我们发现,该菜单项的标识同样也是 ID_EDIT_CUT。因此,我们就知道了,如果要把工具栏上的一个工具按钮与菜单栏中的某个菜单项相关联,只要将它们的B设置为同一个标识就可以了。
如果希望禁用【文件】子菜单下的【新建】菜单项(其ID为 ID_FILE_NEW),则首先可以利用ClassWizard为这个菜单项添加一个UPDATE_COMMAND_UI消息响应函数。然后在此函数中加入例6-17所示代码中加灰显示的那行代码。
例6-17
void CMainFrame: :OnUpdateFileNew(CCmdU工* pCmdU工) pCmdUI->Enable(FALSE);
Build并运行Menu程序,打开【文件】子菜单,就会发现【新建】菜单项变成灰色显示的了,即被禁用了。如图6.27所示。同样,工具栏上的【新建】按钮也变灰了。
'
图 6.27禁用新建菜单项的效果
另外, CCmdUI类有一个m nID成员变量,用于保存当前菜单项、工具栏按钮,或者是其他由 CCmdUI对象表示的U对象的标识。例如,我们可以在上面创建的【新建】菜单项的回DA四,_COMMAND_UI消息响应函数中添加一个判断,判断当前是否是新建菜单项,该函数最后的实现代码如例6-18所示。
~IJ 6-18
void CMainFrame::OnUpdateFileNew(CCmdUI* pCmdUI)
{
if(ID_FILE_NEW pCmdUI->m_nID)
pCmdUI->Enable(FALSE) ;
笔者注: MFC调用采单命令史新函数时,已经确定了特定的菜单项,实际应用时无须判断,此处只是为7介绍知识,因
此做一个判断。
与前面介绍的几个 CMenu类的成员函数一样,这里除了能够利用标识来访问菜单项以外,还可以利用菜单项的位置索引来访问。 CCmdUI类还有一个成员变量:m-血dex,
~..‘ I 187
保存了当前菜单项的位置索引。于是,我们可以把上述例6-18所示代码中的判断语句修改为下面这条语句(注:【新建】菜单项的位置索引为0) :
if(O == pCrndUI->rn-p工ndex) ,
下面,我们利用位置索引的方式来实现使【剪切】菜单可用这一功能。在资源编辑器中打开菜单资源,计算【剪切】菜单项的位置索引,可以得到结果是 2,记住:计算菜单项索引时,一定要把分隔栏菜单项计算在内。然后,修改前面创建的【剪切】菜单项消息响应函数: OnUpdateEditCut,修改后的代码如例6-19所示。
锣IJ 6-19
void CMainFrarne : :OnUpdateEditCut(CCrndUI* pCrndUI) // TODO: Add your cornrnand update U工 handler code here if(2 --pCrndU工->rn_n工ndex) pCrndUI->E口able ( ) ;
Build并运行Menu程序,打开【编辑】子菜单,发现【剪切】菜单项变成可用的了,但是,我们却发现这时工具栏上的【剪切】按钮仍是变灰的。为什么会出现这样的情况呢?如果我们把上述代码中位置索引换成【剪切】菜单项的标识会产生什么样的结果呢?读者可以试一下,将会发现这时工具栏上的剪切按钮也变成可用的了。那为什么使用标识就可以,使用位置索引就不行呢?这是因为菜单项和工具按钮的位置索引计算方式不同。对于菜单项来说,它的索引是从其所在子菜单下的第1个菜单项开始从O开始计数,但对于工具栏上的工具按钮来说,它是以工具栏上最前面的那个按钮为起始位置从O开始计数。因此,在Menu这个例子中,【剪切】菜单项的位置索引是2,但工具栏上的【剪切】按钮的位置索引却是4(同样,工具栏上的分隔符的位置也要计算在内)。正是因为它们二者的位置索引值不一样,所以在上述程序中就出现了二者的状态不一致的情况。因为菜单项和工
, 具栏按钮的位置索引并不是一一对应的,所以,读者在编程时,为了
Jr:I..!x一致,最好采用菜单项标识或工具栏按钮标识的方式来进行设置。综上所述,如果要在程序中设置某个菜单项的状态,首先通过 ClassWüard为这个菜单项添加UPDATECO岛1MAND UI消息响应函数,然后在这个函数中进行状态的设置即可。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -