在MFC环境下开发PocketPC 2002应用程序时,命令栏中嵌入菜单是一个常见的需求。然而,实现这一功能并非易事。本文将探讨如何在MFC中实现这一功能,并提供一个可行的解决方案。
命令栏中的顶级弹出菜单实际上并不是真正的弹出菜单,而是工具栏按钮。这是通过对CCeCommandBar::LoadToolBar
的实现进行分析得出的结论。提供给它的菜单资源会被分解成各个弹出菜单,然后为每一个弹出菜单创建一个文本工具栏按钮。因此,尝试使用CMenu
方法来启用或禁用这些按钮是没有用的,必须操作底层的按钮。
弹出菜单按钮的创建使用了标准ID,从0xF000开始,并且每个后续按钮的ID递增1。因此,要访问想要操作的按钮,必须知道它的序数位置。如果使用的是“共享新”按钮,那么0xF000将是它右侧的第一个按钮。
第一种方法是使用TB_ENABLEBUTTON
消息。这似乎有效,直到John Simmons注意到,当按钮被禁用时,一些按钮的文本会被截断。事实上,当工具栏禁用一个文本按钮时,它会用带有白色阴影的灰色来绘制它,使得文本宽度增加一个像素。毫无疑问,容纳这些文本的矩形没有改变,因此文本被剪切了...
接下来的方法是基于CToolBarCtrl
的GetButtonInfo
和SetButtonInfo
方法,这些方法支持所有工具栏。通过这些方法,设置了TBBUTTONINFO
结构的多个属性,分别是fsState
和cx
。第一个用于设置按钮状态(启用或禁用),第二个用于在按钮被禁用时增加按钮大小,以及在按钮被启用时减小它。
将解决方案封装在CCeCommandBarEx
类中,该类除了标准的构造函数和析构函数外,只有一个方法:EnablePopupMenu
。实现如下:
BOOL CCeCommandBarEx::EnablePopupMenu(int iIndex, BOOL bEnable) {
CToolBarCtrl& rToolBar = GetToolBarCtrl();
TBBUTTONINFO tbi;
int nID = 0xf000 + iIndex;
CSize sizeImage(16, 15), sizeButton(23, 21);
BOOL bRval;
tbi.cbSize = sizeof(tbi);
tbi.dwMask = TBIF_STATE | TBIF_SIZE | TBIF_COMMAND;
tbi.idCommand = nID;
bRval = rToolBar.GetButtonInfo(nID, &tbi);
if (bRval) {
if (tbi.fsState & TBSTATE_ENABLED)
tbi.cx += bEnable ? 0 : 1;
else
tbi.cx -= bEnable ? 1 : 0;
if (bEnable)
tbi.fsState |= TBSTATE_ENABLED;
else
tbi.fsState &= ~TBSTATE_ENABLED;
rToolBar.SetButtonInfo(nID, &tbi);
SetSizes(sizeButton, sizeImage);
}
return bRval;
}
注意,必须调用SetSizes
来避免发现的一个难以理解的bug:当增加弹出菜单按钮大小时,所有其他按钮也会改变它们的大小。
会发现演示项目是对在另一篇文章PocketPC2002中的多个工具栏中使用的项目进行了一些修改,主要变化包括: