CmenuModifier - 一个自定义绘制的图像菜单






3.92/5 (9投票s)
CmenuModifier - 一个自定义绘制的图像菜单
特点
该类CMenuModifier
面向MFC程序,具有以下特点:
- 可信
它使用原始的拥有绘制方法来修改现有菜单(
CMenu
),因此它是可信的(与使用另一个菜单替换现有菜单相比),并且占用的内存更少。 - 为任何级别的子菜单添加图像
我使用了一些从CodeProject下载的菜单类,但那些类只能为顶层子菜单添加图像。这就是我创建这个类的原因。
- 适用于所有MFC应用程序,例如SDI、MDI、对话框菜单和跟踪弹出菜单。
类文件
所有代码都包含在“Class”目录下的CMenuModifier.h中(没有CPP文件)。
你只需要在你的程序中包含头文件。
图像和透明色
要使用图像,必须将一个CToolBar
实例传递给SetOwnerDraw(...)
函数。CToolBar
实例可以是全局变量也可以是局部变量。
如果没有CToolBar
实例,则不会向菜单添加图像。
重要
CToolBar
上第一个按钮(左上角)的**第一个像素**的颜色代表**透明色**。
当图像绘制在菜单上时,颜色将对背景(菜单垂直条)透明——请参见下面的示例4。
类实例
CMenuModifier
的实例必须是类成员或全局变量,因为它被两个消息使用
WM_DRAWITEM
和WM_MEASUREITEM
- 静态菜单每个静态菜单,如SDI、MDI和对话框主菜单,都需要一个
CMenuModifier
实例。 - 跟踪弹出菜单一个窗口中的所有跟踪弹出菜单只需要一个
CMenuModifier
实例。
你可以为每个跟踪弹出菜单使用一个实例。
函数和用法
必须使用以下三个函数:
-
BOOL SetOwnerDraw (CMenu*pMenu,BOOL bMainMenu,CToolBar*pBar=NULL, int iImageStyle=CCMenuModifier::FLATE, COLORREF*pClrMenuBar=NULL, COLORREF*pClrVertBar=NULL, COLORREF*pClrSelected=NULL);
当菜单准备好时调用此函数。
函数参数,均为“输入”值。CMenu*pMenu
要修改的菜单 BOOL bMainMenu
主菜单为 True
,跟踪弹出菜单为false
CToolBar*pBar
图像工具栏,如果不用图像则为 NULL
int iImageStyle
启用的图像样式,如果 pBar
为NULL
则不使用——请参见下面的示例3。COLORREF *pClrMenuBar
菜单栏颜色的指针,如果为 NULL
则使用默认颜色COLORREF *pClrVertBar
垂直条颜色的指针,如果为 NULL
则使用默认颜色COLORREF*pClrSelected
选中项颜色的指针,如果为 NULL
则使用默认颜色 -
BOOL OnMeasureItem (int nIDCtl, MEASUREITEMSTRUCT*pMIS);
在消息处理程序中调用此函数
OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)
-
BOOL OnDrawItem (int nIDCtl, DRAWITEMSTRUCT*pDIS);
在消息处理程序中调用此函数
OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
如果需要修改多个菜单,调用函数2和3的最佳方式是
例如,md_Main
和md_Popup
的CMenuModifier
实例用于修改主菜单和跟踪弹出菜单。以下代码将加快修改速度:
BOOL b=md_Main.OnDrawMeasureItem(...);
if(b==0) b=md_Popup.OnDrawMeasureItem(...);
上述代码优化并加速了拥有绘制过程。
然而,以下四个示例没有以上述优化方式调用这两个函数,因为菜单项的数量并不太多。
以下函数是可选使用的
void SetChechedItemStyle (BOOL bUseObmBitmap);
如果bUseObmBitmap
为true
(默认),则选中菜单项的图像是Windows OBM复选框。否则
- 如果选中的菜单项有图像,则该图像显示为带有凹陷3D边框,以指示它已被选中。
- 如果选中的菜单项没有图像,则显示Windows OBM复选框。
内部类
有五个内部类
BitmapBuffer
用于存储位图位的缓冲区,简单易用。
BitmapUnit
包含启用和禁用位图。
MenuUser
该类的指针作为参数
lpszNewItem
添加到Windows菜单函数中。ModifyMenu( UINT nPosition, UINT nFlags, UINT nIDNewItem, LPCTSTR lpszNewItem);
MenuUserArray
一个排序数组,用于存储
MenuUser
的指针,可以更快地在数组中搜索MenuUser
的指针。
Windows菜单在拥有绘制模式下,并非完全面向对象,它直接测量和绘制菜单项,而不考虑最顶层的菜单ID。
在数组中快速搜索对于窗口有多个菜单(例如主菜单和跟踪弹出菜单)且菜单项较多的情况很重要且高效。ObmChecked
加载
OBM_CHECK
图像用于选中的菜单项。
示例
压缩文件中包含四个示例。
1. SDI示例
该示例修改了3个菜单:一个主框架菜单和两个跟踪弹出菜单。
因此,该示例包含两个CMenuModifier
实例,一个用于主菜单,另一个用于2个跟踪弹出菜单。
2. MDI示例
该示例包含三个CMenuModifier
实例,一个用于主框架菜单,一个用于子窗口菜单,另一个用于2个跟踪弹出菜单。
3. 对话框示例
该示例修改了3个菜单:一个主菜单和两个跟踪弹出菜单。
因此,该示例包含两个CMenuModifier
实例,一个用于主菜单,另一个用于2个跟踪弹出菜单。CToolBar
实例是示例中的局部变量。
该示例更改了启用图像样式。
下图所示的菜单是跟踪弹出菜单。
在深色菜单垂直条上,启用的图像比平面样式看起来更突出、更漂亮。
4. 彩色对话框示例
CToolBar
实例是示例中的全局变量(类成员)。
该示例更改了菜单栏颜色以匹配彩色对话框。
对话框背景颜色由CWinApp::SetDialogBkColor(RGB(191,223,223))
确定。
最终结果是
需要进行两个步骤来实现此目的
1. 在SetOwnerDraw(...)函数中将菜单栏颜色更改为对话框颜色。
此时,菜单看起来像
我尝试在类中以编程方式添加一个比最后一个菜单(本例中的“帮助”菜单)长很多的菜单,以覆盖浅灰色菜单栏的右侧部分,但Windows操作系统不允许这样做——额外长的菜单要么消失,要么被操作系统移到第二行。
2. 添加几个额外的空白、灰色的菜单项
这些菜单项是从VC资源中手动添加的。
此时,菜单看起来像

然后使用一个无模式对话框来覆盖浅灰色菜单栏的右侧部分——这些空白菜单项使得覆盖更容易。
请注意,这一步与该类无关,我只是想展示如何在彩色对话框中使用该类。
限制
- 256色系统设置无效
该类分析
CToolBar
的位图,然后在类内部生成并存储启用和禁用的图像。因此,CToolBar
可以是一个局部变量,并在传递给SetOwnerDraw(...)
函数后立即销毁。限制是计算机系统的颜色设置为16位或32位。如果计算机设置为256色,图像将不会显示——因为我从未修改过256色位图——我认为今天没有人使用这种设置。如果你需要,请修改类的
P_CreateUserImage(...)
函数。 - 动态菜单项无效
该类修改在调用
SetOwnerDraw(...)
函数之前创建的菜单项。
动态菜单项,例如MDI中的“最近打开的文件”或“窗口”,可能随时添加,因此这些菜单项未设置为拥有绘制,并且未被修改。
更多信息
类内部图像的大小比CToolBar
按钮的原始图像大两个像素。
禁用图像在右边框和下边框需要一个额外的像素。样式中的启用图像需要在所有边框上额外一个像素。
下图展示了一个平面图像如何通过在左侧和顶部添加白色线条,在右侧和底部添加深灰色线条,从而被修改为凸起的两种样式。

最后的提示
- 再次提醒
工具栏的第一个像素代表透明色。通常,该颜色应为浅灰色。“透明”意味着颜色将被更改为图像背景色或菜单垂直条的颜色。
- 超级计算器
这款计算器可以计算矩阵、向量、复数、定积分、方程根、常用函数(如正弦、对数)、统计、绘制轨迹等,功能众多,是我比较满意的程序之一,希望你也喜欢,它是免费的。
这个提示是一个附带的礼物,与菜单类无关。
历史
-
2008年6月3日:首次发布