MFC中用户界面元素更新原理(UPDATE_COMMAND_UI)_第1页
MFC中用户界面元素更新原理(UPDATE_COMMAND_UI)_第2页
MFC中用户界面元素更新原理(UPDATE_COMMAND_UI)_第3页
MFC中用户界面元素更新原理(UPDATE_COMMAND_UI)_第4页
MFC中用户界面元素更新原理(UPDATE_COMMAND_UI)_第5页
全文预览已结束

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、大家在编程的过程中一定遇到过这种情况:需要根据某个变量的值来设定菜单项是否被选中,设置工具栏按钮是否被按下或者在状态栏中显示一些信息。MFC提供了一种机制来帮助我们完成这项工作:只要用ClassWizard给相应的菜单项或者工具栏按钮添加一个UPDATE_COMMAND_UI处理函数,在其中用CcmdUI:SetCheck等函数来设置这些用户界面元素的状态就可以了。但是MFC是怎么实现这个功能的呢?首先让我们来看看菜单状态更新的实现方法。首先要知道,当你点现了一个有子菜单的菜单项时(比如菜单栏上的“文件”),系统会向拥有这个菜单的窗口发送一个WM_INITMENUPOPUP,下面是MFC对这个

2、消息的默认处理:voidCFrameWnd:OnInitMenuPopup(CMenu* pMenu, UINT nIndex, BOOL bSysMenu) /为了说明问题,我省略了很多代码CCmdUI state;state.m_pMenu = pMenu;state.m_nIndexMax = pMenu-GetMenuItemCount();for (state.m_nIndex = 0; state.m_nIndex GetMenuItemID(state.m_nIndex); if (state.m_nID = (UINT)-1)/m_nID=-1表示它下面还有popup menu

3、(就那种带右箭头的菜单项),/它是不会自动deisable的elsestate.m_pSubMenu = NULL;state.DoUpdate(this, m_bAutoMenuEnable & state.m_nID OnCmdMsg(m_nID,CN_UPDATE_COMMAND_UI,this, NULL);if (bDisableIfNoHndler & !m_bEnableChanged)AFX_CMDHANDLERINFO info;info.pTarget = NULL;BOOL bHandler = pTarget-OnCmdMsg(m_nID, CN_COMMAND, th

4、is, &info);Enable(bHandler);return bResult;DoUpdate的流程就是:先向你的菜单项发一个CN_UPDATE_COMMAND_UI命令消息,让你的菜单项来进行显示前的更新,这就是你在classwizard中可以看到的UPDATE_COMMADN_UI消息,你加的处理函数就是在这个时候被调用的。如果你处理了CN_UPDATE_COMMAND_UI,那么m_bEnableChanged就变成true,接下来就直接返回了。否则,如果bDisableIfNoHndler也为true,那么就向菜单项发一个CN_COMMAND消息,如果你不响应这个消息,说明这个

5、菜单项还没有处理函数,那么,bnHandler就是flase,然后Enable(false)就把你的菜单项变灰了。注意在CFrameWnd:OnInitMenuPopup中调用DoUpdate时的参数是m_bAutoMenuEnable & state.m_nID0xF000,这说如果你一开始就把m_bAutoMenuEnable设为false的话,实际上就关闭了MFC自动diable没有处理函数的菜单项的功能。工具栏的更新用的是另外一套方法。首先需要知道当你的的程序变得空闲,没有消息需要处理的时候,MFC会调用CWinApp:OnIdle函数利用这个时间进行一些特殊的工作,其中之一就是更新你

6、的工具栏和状态栏。下面来看相关的代码: BOOL CWinThread:OnIdle(LONG lCount)if (lCount m_hWnd != NULL & pMainWnd-IsWindowVisible()AfxCallWndProc(pMainWnd, pMainWnd-m_hWnd, WM_IDLEUPDATECMDUI, (WPARAM)TRUE, 0); pMainWnd-SendMessageToDescendants(WM_IDLEUPDATECMDUI,(WPARAM)TRUE, 0, TRUE, TRUE);/接下来向本线程创建的所有frame window发送WM

7、_IDLEUPDATECMDUI消息 AFX_MODULE_THREAD_STATE* pState=_AFX_CMDTARGET_GETSTATE()-m_thread;CFrameWnd* pFrameWnd = pState-m_frameList;while (pFrameWnd != NULL)if(pFrameWnd-IsWindowVisible()|pFrameWnd-m_nShowDelay = 0) AfxCallWndProc(pFrameWnd, pFrameWnd-m_hWnd,WM_IDLEUPDATECMDUI, (WPARAM)TRUE, 0);pFrameWn

8、d-SendMessageToDescendants(WM_IDLEUPDATECMDUI,(WPARAM)TRUE, 0, TRUE, TRUE);你的toolbar或者statusbar总是某个frame window的子窗口(包括子窗口的子窗口),所以它肯定能收到WM_IDLEUPDATECMDUI消息。CToolBar和CStatusBar都是从CControlBar派生的,下面是CControlBar对这个消息的处理: LRESULT CControlBar:OnIdleUpdateCmdUI(WPARAM wParam, LPARAM) if (GetStyle() & WS_VI

9、SIBLE) )/将pTarget指向离this最近的父frame windowCFrameWnd* pTarget = (CFrameWnd*)GetOwner();if (pTarget = NULL | !pTarget-IsFrameWnd() pTarget = GetParentFrame();/调用虚成员函数OnUpdateCmdUIif (pTarget != NULL)OnUpdateCmdUI(pTarget, (BOOL)wParam);return 0L;OnUpdateCmdUI是CControlBar类的一个纯虚函数,CToolBar中对这个函数进行了定义:void

10、 CToolBar:OnUpdateCmdUI(CFrameWnd* pTarget, BOOLbDisableIfNoHndler)CToolCmdUI state;state.m_pOther = this;state.m_nIndexMax = DefWindowProc(TB_BUTTONCOUNT, 0, 0); /工具栏上的按钮数for (state.m_nIndex=0; state.m_nIndex state.m_nIndexMax; state.m_nIndex+)/如果你派生了自己的CToolBar类,那么先让执行你定义的处理函数来进行状态更新if (CWnd:OnCmd

11、Msg(state.m_nID, CN_UPDATE_COMMAND_UI, &state, NULL)continue;/如果toolbar没有更新自己,让pTarget(也就是离它最近的父frame window)来更新它。比如对于MFC自动生成的SDI框架来说,pTarget会指向CMainFrame state.DoUpdate(pTarget, bDisableIfNoHndler); /如果CToolBar中有用户创建的控件,也一起更新UpdateDialogControls(pTarget, bDisableIfNoHndler);CCmdUI:DoUpdate的代码上面已经列出

12、过了。至此,工具栏和状态栏也能顺利也进行更了。有经验的朋友应该知道,如果你在一个基于对话框的程序里模仿doc/view结构中的方法使用UPDATE_COMMAND_UI来更新用户界面元素的话是不会有任何效果的。其原因是一个模态对话显示出来以后,程序就会进入这个对话框自己的消息循环(看看DoModal的源码就能了解这一点),此时不会再有WM_IDLEUPDATECMDUI被发送到这些界面元素中。下面说说这种情况下的解决办法,你可以自己查看MFC的源码来弄清它的原理:首先加一个头文件afxpriv.h(其中定义了KICKIDLE消息),然后添加一个消息映射来处理WM_KICKIDLE消息:ON_M

13、ESSAGE(WM_KICKIDLE,OnKickIdle)。其中OnKickIdle定义如下: LRESULT CTabDialog:OnKickIdle(WPARAM wp, LPARAM lCount)UpdateDialogControls(this, TRUE);return 0;完成这些工作以后,你就可以顺利地使用UPDATE_COMMAND_UI机制了。 -CCmdUICCmdUI没有基类它仅在一个CCmdTarget派生类的ON_UPDATE_COMMAND_UI处理程序中使用。当用户在应用的下拉菜单时,要确定每个菜单项的显示状态允许存取或禁止存取。菜单命令的目标通过实现一个O

14、N_UPDATE_COMMAND_UI处理来提供这些信息。可以使用ClassWizard来浏览定位应用中的命令用户接口对象,然后为它建立一个消息映射入口,并为每个消息处理函数提供函数原型。当菜单被下拉时,框架搜索并调用每个ON_UPDATE_COMMAND_UI处理,每个处理调用Enable和Check之类的成员函数,相应地,框架就可以正确地显示每个菜单项了。菜单项可以用控件条按钮或者其它的命令用户接口对象替换,而在ON_UPDATE_COMMAND_UI处理中的代码不需要改动。下表列出了各种命令用户接口上的CCmdGUI的成员函数。用户接口项 Enable SetCheck SetRadio SetText菜单项 允许或禁止存取该项 选中()或未选中 选中(有黑点) 设置项的文本工具条按钮 允许或禁止存取该项 选中、未选中或不定 (不可用) 与SetCheck相同状态条状态提示 文本可见或不可

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论