MFC中PocketPC 2002应用的命令栏菜单实现

在MFC环境下开发PocketPC 2002应用程序时,命令栏中嵌入菜单是一个常见的需求。然而,实现这一功能并非易事。本文将探讨如何在MFC中实现这一功能,并提供一个可行的解决方案。

命令栏中的顶级弹出菜单

命令栏中的顶级弹出菜单实际上并不是真正的弹出菜单,而是工具栏按钮。这是通过对CCeCommandBar::LoadToolBar的实现进行分析得出的结论。提供给它的菜单资源会被分解成各个弹出菜单,然后为每一个弹出菜单创建一个文本工具栏按钮。因此,尝试使用CMenu方法来启用或禁用这些按钮是没有用的,必须操作底层的按钮。

弹出菜单按钮的创建使用了标准ID,从0xF000开始,并且每个后续按钮的ID递增1。因此,要访问想要操作的按钮,必须知道它的序数位置。如果使用的是“共享新”按钮,那么0xF000将是它右侧的第一个按钮。

解决方案

第一种方法是使用TB_ENABLEBUTTON消息。这似乎有效,直到John Simmons注意到,当按钮被禁用时,一些按钮的文本会被截断。事实上,当工具栏禁用一个文本按钮时,它会用带有白色阴影的灰色来绘制它,使得文本宽度增加一个像素。毫无疑问,容纳这些文本的矩形没有改变,因此文本被剪切了...

接下来的方法是基于CToolBarCtrlGetButtonInfoSetButtonInfo方法,这些方法支持所有工具栏。通过这些方法,设置了TBBUTTONINFO结构的多个属性,分别是fsStatecx。第一个用于设置按钮状态(启用或禁用),第二个用于在按钮被禁用时增加按钮大小,以及在按钮被启用时减小它。

将解决方案封装在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中的多个工具栏中使用的项目进行了一些修改,主要变化包括:

  • 所有工具栏上都有工具提示。
  • 工具栏现在只显示在特定条件下。
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485