简单位图菜单
这篇文章由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 );
}
全文完。