CMenu类

 

在MFC中,排除调用API函数那种复杂的方法之外,就只有CMenu这个类可以让我们来控制菜单了。对于这个类,琢磨了两天,总算有点心得。
对于系统菜单,创建起来比较简单,直接使用资源编辑器就能生成菜单,再通过ClassWizard创建菜单命令函数。在我的资源中上传了一个工程,实现了一个右键弹出贴图菜单。结合这个工程,介绍动态创建菜单、创建弹出式菜单和重绘菜单。
首先介绍基础知识:
一、CMenu类的成员函数:
1.       CreateMenu()和CreatePopupMenu(),这两个函数用来创建一个菜单实例,CreateMenu()创建的是普通的菜单实例,如果想创建弹出式菜单,就要用CreatePopupMenu()函数。
2.       AppendMenu()向菜单中添加一个子项,这个函数有两个主要的参数。第一个UINT nFlags ,这个参数表明了该子项的属性特征,可以这样说,这个参数规定了菜单的样式和功能。后面会详细讲这个参数所能使用的值。第二个参数 UINT_PTR nIDNewItem ,根据 nFlags 使用不同的设置,该参数将标明菜单的资源 ID 或在这个菜单中的索引号。第三个参数可以省略,如果不省略,可以传入一个字符串,这个字符串将显示在菜单中(因为我准备用图片表示菜单项,所以我的工程中省略了这个参数)。
3.       DrawItem() ,这是一个虚函数,如果菜单设置成可以自绘类型,则这个函数将在生成菜单、弹出菜单、选中菜单、点击菜单等时由系统框架调用。因此,这个函数是一个很有用的函数,它可以帮你绘制出各种样式的菜单。
4.       MeasureItem() 也是一个虚函数,当菜单被创建的时候由系统框架调用。这个函数用来设置菜单的大小。
二、 nFlags 说明:
只有当 nFlags 设置成MF_OWNERDRAW的时候,系统框架才会重绘菜单。
MF_CHECKED:命令旁显示默认复选标志
MF_UNCHECKED:清除命令旁的复选标志
MF_DISABLED:禁止此菜单命令,但是不变灰显示
MF_ENABLED:允许此菜单命令,恢复到正常状态
MF_GRAYED:禁止此菜单命令,变灰显示
MF_MENUBARBREAK:对于静态菜单,放到新行;对于弹出菜单,放到新栏 中,栏间有分隔线
MF_MENUBREAK:对于静态菜单,放到新行;对于弹出菜单,放到新栏,栏间雾分隔线
MF_OWNERDRAW:指定该命令是自画式菜单命令
MF_POPUP:指定该菜单命令有一个关联的弹出式菜单
MF_SEPARATOR:画一条水平分隔线,只用于弹出式菜单
MF_STRING:指定此菜单命令是一个字符串
 
三、开始工程:
1. 创建一个基于对话框的工程。然后添加一个新类,这个新类从CMenu继承。这个地方值得注意:如果使用ClassWizard添加新类的话,你会发现在基类的列表中找不到CMenu。所以,只能自己创建两个文件,然后自己写代码了。
2. 我们给新类取名CBmpMenu,重载CMenu的 DrawItem() MeasureItem() 这两个虚函数。
头文件:
class CBmpMenu : public CMenu 
{
public:
CBmpMenu();
virtual ~CBmpMenu();
virtual void DrawItem(LPDRAWITEMSTRUCT lpDIS);
virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
};
3.
void CBmpMenu::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
          lpMeasureItemStruct->itemWidth=50;
          lpMeasureItemStruct->itemHeight=18;
}
可以看的很清楚,lpMeasureItemStruct->itemWidth表示菜单的宽度, itemHeight表示菜单的高度,重新设置你想设置的值。
4.工程添加了两组图片资源,每一组五张,一组表示普通模式下的图片,一种表示当选中菜单时显示的图片。要使菜单弹出时显示图片,则重载 DrawItem 函数,并在 DrawItem 函数中绘制图片。
void CBmpMenu::DrawItem(LPDRAWITEMSTRUCT lpDIS)
{
       CDC* pDC=CDC::FromHandle(lpDIS->hDC);
       CDC dcmem;
       dcmem.CreateCompatibleDC(pDC);
       CBitmap * bt=new CBitmap;
       if((lpDIS->itemState & ODS_SELECTED) &&
              (lpDIS->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)))
       {
              switch(lpDIS->itemID)
              {
              case IDR_MENU:
                     bt->LoadBitmap(MAKEINTRESOURCE(IDB_HOT_50));
                     break;
              case IDR_MENU+1:
                     bt->LoadBitmap(MAKEINTRESOURCE(IDB_HOT_100));
                     break;
              case IDR_MENU+2:
                     bt->LoadBitmap(MAKEINTRESOURCE(IDB_HOT_150));
                     break;
              case IDR_MENU+3:
                     bt->LoadBitmap(MAKEINTRESOURCE(IDB_HOT_200));
                     break;
              case IDR_MENU+4:
                     bt->LoadBitmap(MAKEINTRESOURCE(IDB_HOT_FULL));
                     break;
              }
       }
       else
       {
              switch(lpDIS->itemID)
              {
              case IDR_MENU:
                     bt->LoadBitmap(MAKEINTRESOURCE(IDB_NORMAL_50));
                     break;
              case IDR_MENU+1:
                     bt->LoadBitmap(MAKEINTRESOURCE(IDB_NORMAL_100));
                     break;
              case IDR_MENU+2:
                     bt->LoadBitmap(MAKEINTRESOURCE(IDB_NORMAL_150));
                     break;
              case IDR_MENU+3:
                     bt->LoadBitmap(MAKEINTRESOURCE(IDB_NORMAL_200));
                     break;
              case IDR_MENU+4:
                     bt->LoadBitmap(MAKEINTRESOURCE(IDB_NORMAL_FULL));
                     break;
              }
       }
       dcmem.SelectObject(bt);
       pDC->BitBlt(lpDIS->rcItem.left,lpDIS->rcItem.top,61,18,&dcmem,0,0,SRCCOPY);
}
LPDRAWITEMSTRUCT 类型的参数包含 9 个域:
typedef struct tagDRAWITEMSTRUCT {
   UINT CtlType;
   UINT CtlID;
   UINT itemID;
   UINT itemAction;
   UINT itemState;
   HWND hwndItem;
  HDC hDC;
   RECT rcItem;
   DWORD itemData;
} DRAWITEMSTRUCT;
CtlType :表示重绘的对象,因为不光菜单可以重绘,其他的一些资源也可以。ODT_BUTTON、ODT_COMBOBOX  、ODT_LISTBOX 、ODT_MENU  、ODT_LISTVIEW   、ODT_STATIC   、ODT_TAB 。
CtlID :控件资源的 ID 号,如果对菜单重绘,那么这个域不使用。
itemID :在这里表示菜单项的 ID
itemAction :表示发生什么动作导致重绘。
itemState :表示当前重绘资源所处的状态,例如被点击,被选中。
各种动作和状态 MSDN 中做了详细说明,可在 MSDN2003 Visual Studio . Net/Visual C++/ Visual C++ 参考 / Visual C++ libraries/MFC Reference/Structures…/Structures by MFC/ DRAWITEMSTRUCT Structure中找到。
hwndItem :控件窗体的句柄,如果是菜单,则表示菜单的句柄。
hDC :要重绘的区域的设备内容,重绘的所有动作都靠它。
rcItem :重绘区域的坐标。
itemData :添加菜单时设定的值,由于我们省略了AppendMenu()的第三个参数,所以这里不用关心它。
看完这些介绍,我们大致可以明白如何重新绘制菜单了,也就是使用 hDC rcItem 区域绘图,至于绘制什么图,可以根据 itemID 表示的不同的子项, itemAction 表示的不同的动作, itemState 表示子项的不同的状态来绘图。
此工程就是根据是否选中菜单 if((lpDIS->itemState & ODS_SELECTED) &&(lpDIS->itemAction & (ODA_SELECT | ODA_DRAWENTIRE))) 』绘制不同状态的图。
同时判断一下 ID switch(lpDIS->itemID)
 
 
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值