简单位图菜单
这篇文章由Burchak Alexander原著。
有时应用程序使用动态创建的工具条。为什么我要为了位图菜单而创建工具条资源呢?(查看Iuri Apollonio 文章)
我提议装配菜单位图时使用标准位图表。我这个类的优点是位图和工具条图像可以用尺寸和视图等来区分。此类支持SDI和MDI用户界面中的弹出菜单。若你发现了bugs请提出来。
所有你对类CbitmapMenu要做的事是:
1. 添加CbitmapMenu类的实例给CmainFrame 类:
CbitmapMenu m_menu;
2. 添加一个CimageList对象。例如,给CmainFrame类添加其static 成员 :
CimageList m_imglist;
At the point you have in MainFrm.h:
#include "BitmapMenu.h" class CMainFrame : public CMDIFrameWnd { ... public : CBitmapMenu m_menu; static CImageList m_imglist; ... };
在MainFrm.cpp中添加:
#include "MainFrm.h"CImageList CMainFrame :: m_imglist;
3.给这个项目添加N个图象资源。其中一个作为checkmark.
4.为菜单项添加一组CitemBitmap 对象(比如添加到MainFrm.cpp中),这些菜单项将显示位图。
CItemBitmap g_ibs[ ] = { CItemBitmap(ID_FILE_NEW, &CMainFrame :: m_imglist, 0), CItemBitmap(ID_FILE_OPEN, &Camp;MainFrame :: m_imglist, 1), CItemBitmap(ID_HELP_CONTENTS, &CMainFrame :: m_imglist, 19), CItemBitmap(-1, NULL, 0, &CMainFrame :: m_imglist, 27) };
CitemBitmap类有2个构造器:
CItemBitmap( UINT uID,CImageList *pilNormal,UINT uPosNormal); CItemBitmap( UINT uID,CImageList *pilNormal,UINT uPosNormal,CImageList *pilChecked, UINT uPosChecked);其中,
uID---菜单项ID,
pilNormal---CimageList 对象指针,使用一个位图作为“正常”菜单项状态,
pilChecked--- CimageList 对象指针,使用一个位图作为“检查”菜单项状态,
uPosNormal---在pilNormal图像列表中的图像索引,
uPosChecked---在pilChecked图像列表中的图像索引,
列表中的最后个CitemBitmap对象用来保存checkmark图象信息。
这个CbitmapMenu类用来画checked状态的菜单项。
5.在CmainFrame::OnCreate()函数中处理如下:
m_menu.Initialize(IDR_MAINFRAME, this); m_menu.AddBitmaps( g_ibs,sizeof(g_ibs) / sizeof(CItemBitmap));6. 在CmainFrame 类中添加WM_MEASUREITEM, WM_DRAWITEM 和WM_INITMENUPOPUP 消息处理函数。
添加CmainFrame 类的消息映射:
ON_WM_MEASUREITEM( ) ON_WM_DRAWITEM( )ON_WM_INITMENUPOPUP( )
在CmainFrame类中添加下边函数:
void CMainFrame :: OnMeasureItem(int nIDCtl,LPMEASUREITEMSTRUCT lpMIS) { if(lpMIS->CtlType == ODT_MENU) m_menu.MeasureItem( lpMIS ); else CMDIFrameWnd :: OnMeasureItem(nIDCtl, lpMIS); } void CMainFrame :: OnDrawItem(int nIDCtl,LPDRAWITEMSTRUCT lpDIS) { if(lpDIS->CtlType == ODT_MENU) m_menu.DrawItem( lpDIS ); else CMDIFrameWnd :: OnDrawItem(nIDCtl, lpDIS); } void CMainFrame :: OnInitMenuPopup(CMenu *pPopup,UINT nIndex,BOOL bSysMenu) { CMDIFrameWnd :: OnInitMenuPopup( pPopup,nIndex,bSysMenu); if( !bSysMenu ) CBitmapMenu :: Synchronize( pPopup ); }6.可选: 如果你想在视类中使用弹出式位图菜单,可按如下:
CMenu menu;
VERIFY( menu.LoadMenu( SOME_POPUP_MENU_RESOURCE_ID ) );
CMenu *pMenu = (CMenu *) menu.GetSubMenu( 0 );
ASSERT(pMenu != NULL);
pMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON, x, y, AfxGetMainWnd( ));
我们在TrackPopupMenu()中使用AfxGetMainWnd(),让主框架更新菜单项状态。如果你欲要使用“this”作为弹出菜单的父类,会存在两个问题:
1. 你需要手工check/gray/enable/disable 菜单项。
2. 你需要为了适当的绘制位图菜单而添加下面三个消息处理函数。
我并没提供第一个问题的解决办法。第二个问题的办法是在CmainFrame类中为相同消息添加处理函数:
ON_WM_MEASUREITEM( ) ON_WM_DRAWITEM( )ON_WM_INITMENUPOPUP( )
处理体如下:
void CMyEditView :: OnMeasureItem(int nIDCtl,LPMEASUREITEMSTRUCT lpMIS) { if(lpMIS->CtlType == ODT_MENU) ((CMainFrame *) AfxGetMainWnd( ))->m_menu.MeasureItem( lpMIS ); else CEditView :: OnMeasureItem(nIDCtl, lpMIS); } void CMyEditView :: OnDrawItem(int nIDCtl,LPDRAWITEMSTRUCT lpDIS) { if(lpDIS->CtlType == ODT_MENU) ((CMainFrame *) AfxGetMainWnd( ))->m_menu.DrawItem( lpDIS ); else CEditView :: OnDrawItem(nIDCtl, lpDIS); } void CMyEditView :: OnInitMenuPopup(CMenu *pPopup,UINT nIndex,BOOL bSysMenu) { CEditView :: OnInitMenuPopup(pPopup,nIndex,bSysMenu); if( !bSysMenu ) CBitmapMenu :: Synchronize( pPopup ); }全文完。