WEB开发网
开发学院软件开发VC MFC教程(13)-MFC工具条和状态栏(2) 阅读

MFC教程(13)-MFC工具条和状态栏(2)

 2007-10-04 20:11:26 来源:WEB开发网   
核心提示:void CToolBar::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler){//定义一个CCmdUI对象,CToolCmdUI派生于CCmdUICToolCmdUI state;//给CCmdUI的各个成员赋值state.m_pOther = th

void CToolBar::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler)
{
//定义一个CCmdUI对象,CToolCmdUI派生于CCmdUI
CToolCmdUI state;
//给CCmdUI的各个成员赋值
state.m_pOther = this;
//得到总的按钮数目
state.m_nIndexMax = (UINT)DefWindowProc(TB_BUTTONCOUNT, 0, 0);
//逐个按钮进行状态更新
for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax; state.m_nIndex++)
{
//获取按钮状态信息
TBBUTTON button;
_GetButton(state.m_nIndex, &button);
//得到按钮的ID
state.m_nID = button.idCommand;
// ignore separators
if (!(button.fsStyle & TBSTYLE_SEP))
{
//优先让CToolBar对象处理状态更新消息
if (CWnd::OnCmdMsg(state.m_nID,
CN_UPDATE_COMMAND_UI, &state, NULL))
continue;//处理了更新消息,更新下一个按钮
//CToolBar没有处理,将发送给pTarget处理状态更新消息
//第二个参数bDisableIfNoHndler往下传
state.DoUpdate(pTarget, bDisableIfNoHndler);
}
}
//更新加到控制条中的对话框控制的状态
UpdateDialogControls(pTarget, bDisableIfNoHndler);
}

CToolBar的OnUpdateCmdUI函数完成工具条按钮的状态更新。它接受两个参数,参数1表示接收状态更新命令消息的对象,由CControlBar的函数OnIdleUpdateCmdUI传递过来,一般是边框窗口对象;参数2表示如果某条命令消息没有处理函数时,对应的用户接口对象是否被禁止。

OnUpdateCmdUI通过发送状态更新通知消息,逐个更新按钮的状态。更新消息首先让工具条对象处理,如果没有处理的话,送给边框窗口对象处理,导致状态更新命令消息的处理函数被调用,参见4.4.5节。

CStatusBar的OnUpdateCmdUI类似于此。

CDialogBar的OnUpdateCmdUI则调用了虚拟函数UpdateDialogControls来进行状态更新,CWnd提供了该函数的实现,过程类似于CToolBar的函数OnUpdateCmdUI。

菜单项的自动更新

那么,菜单项的自动更新如何实现的呢?OnInitMenuPopup在菜单项状态的自动更新中曾经被提到,其实现如下:

void CFrameWnd::OnInitMenuPopup(CMenu* pMenu, UINT, BOOL bSysMenu)
{
AfxCancelModes(m_hWnd);
if (bSysMenu)
return; // don't support system menu
ASSERT(pMenu != NULL);
// check the enabled state of various menu items
CCmdUI state;
state.m_pMenu = pMenu;
ASSERT(state.m_pOther == NULL);
ASSERT(state.m_pParentMenu == NULL);
//判断菜单是否在顶层菜单(top level menu)中弹出,如果这样
//则设置m_pParentMenu指向顶层菜单,否则m_pParentMenu
//为空,表示它是一个二级弹出菜单
HMENU hParentMenu;
//是否是浮动式的弹出菜单(floating pop up menu)
if (AfxGetThreadState()->m_hTrackingMenu == pMenu->m_hMenu)
state.m_pParentMenu = pMenu; // parent == child for tracking popup
else if ((hParentMenu = ::GetMenu(m_hWnd)) != NULL)//
{
CWnd* pParent = GetTopLevelParent();
// child windows don't have menus -- need to go to the top!
//得到顶层窗口的菜单
if (pParent != NULL &&
(hParentMenu = ::GetMenu(pParent->m_hWnd)) != NULL)
{
int nIndexMax = ::GetMenuItemCount(hParentMenu);
//确定顶层窗口的菜单是否包含本菜单项
for (int nIndex = 0; nIndex < nIndexMax; nIndex++)
{
if (::GetSubMenu(hParentMenu, nIndex) == pMenu->m_hMenu)
{
//顶层窗口菜单是本菜单的父菜单
state.m_pParentMenu = CMenu::FromHandle(hParentMenu);
break;
}
}
}
}
//本菜单的菜单项(menu item)数量
state.m_nIndexMax = pMenu->GetMenuItemCount();
//对所有菜单项逐个进行状态更新
for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax;
state.m_nIndex++)
{
state.m_nID = pMenu->GetMenuItemID(state.m_nIndex);
if (state.m_nID == 0)
continue; // menu separator or invalid cmd - ignore it
ASSERT(state.m_pOther == NULL);
ASSERT(state.m_pMenu != NULL);
if (state.m_nID == (UINT)-1)
{
// 可能是一个popup菜单,得到其第一个子菜单项目
state.m_pSubMenu = pMenu->GetSubMenu(state.m_nIndex);
if (state.m_pSubMenu == NULL ||
(state.m_nID = state.m_pSubMenu->GetMenuItemID(0)) == 0 ||
state.m_nID == (UINT)-1)
{
continue; // 找不到popup菜单的子菜单项
}
//popup菜单不会被自动的禁止
state.DoUpdate(this, FALSE);
}
else
{
//正常的菜单项,若边框窗口的m_bAutoMenuEnable设置为
//TURE且菜单项非系统菜单,则自动enable/disable该菜单项
state.m_pSubMenu = NULL;
state.DoUpdate(this, m_bAutoMenuEnable && state.m_nID < 0xF000);
}
//经过菜单状态的更新处理,可能增加或删除了一些菜单项
UINT nCount = pMenu->GetMenuItemCount();
if (nCount < state.m_nIndexMax)
{
state.m_nIndex -= (state.m_nIndexMax - nCount);
while (state.m_nIndex < nCount &&
pMenu->GetMenuItemID(state.m_nIndex) == state.m_nID)
{
state.m_nIndex++;
}
}
state.m_nIndexMax = nCount;
}
}

菜单弹出之前,发送WM_INITMENUPOPUP消息,OnInitMenuPopup消息处理函数被调用,逐个更新菜单项目(menu item)的状态。程序员可以处理它们对应的状态更新消息,禁止/允许菜单项目被使用(disable/enable),在菜单项目上打钩或者取消(checked/unchecked),等等。

上一页  3 4 5 6 7 8 9 10 11  下一页

Tags:MFC 教程 MFC

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接