完美实现真彩自绘菜单
2008-01-19 20:23:56 来源:WEB开发网有了以上的强有力的武器,就可以对我们的程序下手了:)在MDI或SDI中使用CMenuEx的时候需要修改以下地方。
- 先将MenuEx.h和MenuEx.cpp添加到工程中,在CMainFrame中添加头文件,CMenuEx对象,用于存储菜单图像的CImageList对象和初始化菜单程序。
#include "MenuEx.h" // 添加头文件
class CMainFrame : public CMDIFrameWnd
{
...
public:
HMENU InitMainFrameMenu(); // 初始化主菜单
HMENU InitImageTypeMenu(); // 初始化文档模板菜单
protected: // CMenuEx members
CMenuEx m_menuMainFrame; // 主窗体没有打开任何文档时菜单
CMenuEx m_menuImageType; // 主窗体打开文档时菜单(文档模板菜单)
protected: // CMenuEx''s image list members
CImageList m_imageMenu; // 菜单项正常的图像列表
CImageList m_imageMenuDisable; // 菜单项禁用时的图像列表
CImageList m_imageMenuHot; // 菜单项被选中时的图像列表
...
} - 撰写菜单图像索引表,初始化菜单程序,初始化菜单图像列表程序, 和两个重要的消息映射函数CMainFrame::OnMeasureItem()和CMainFrame::OnInitPopupMenu()。 (什么?不会添加!,找ClassWizard帮忙或许有点帮助了:))
// 声明,因为下面的结构要用到 CMenuEx*,又不支持向后引用,又什么办法啊!
当然,要通过资源编辑器的Import功能将他们导入到资源文件中,不过因为是真彩,所以不能用VC的图片编辑器编辑了。 告诉大家个敲门,我是用windows自带的画笔画的:)
class CMenuEx;
//自绘菜单数据项结构,就是要传给系统的那个牛X的LPCTSTR指针所指向的东东
typedef struct tagMENUITEM
{
CString strText; // 菜单名称
UINT nID; // 菜单ID号
// 分割条的ID是 0
// 子菜单的ID是 -1
CSize itemSize; // 菜单项的尺寸,不包括菜单图像的尺寸
CImageList* pImageList; // 菜单项的正常图像列表
CImageList* pDisabledImageList; // 菜单项的禁用图像列表
CImageList* pHotImageList; // 菜单项的选中图像列表
UINT nImageIndex; // 菜单项的图像列表索引,-1表示没有图像
BOOL bIsSubMenu; // 表示当前菜单项是否为子菜单项
CMenuEx* pSubMenu; // 如果是一般菜单,该值为NULL
// 如果bIsSubMenu为TRUE,该值为指向子菜单项的CMenuEx*指针
} MENUITEM,*LPMENUITEM;
///////////////////////////////////////////
// 在ManiFram.cpp 中添加菜单图像索引表
static UINT nMenuImageIndex[] =
{
ID_FILE_OPEN,
ID_FILE_SAVE,
ID_FILE_PRINT,
ID_EDIT_COPY,
ID_EDIT_PASTE,
ID_EDIT_UNDO,
ID_EDIT_REDO,
ID_APP_ABOUT,
ID_IMAGE_LEVEL,
ID_IMAGE_EQUALIZE,
ID_IMAGE_SMOOTH,
ID_IMAGE_SHARP,
ID_IMAGE_SIZE,
ID_IMAGE_RA,
ID_IMAGE_HISTOGRAM,
ID_ZOOMOUT,
ID_ZOOMIN,
};
/////////////////////////////////////////////////////////////////////////////
// 在ManiFram.cpp 中添加初始化菜单程序
void CMainFrame::InitMenuImage()
{
// 初始化菜单图像列表
CBitmap bm;
m_imageMenu.Create(20, 20, TRUE | ILC_COLOR24, 9, 0);
// 要问我IDB_SMALLMENUCOLOR是什么,当然是是真彩位图了,看图说话了
bm.LoadBitmap(IDB_SMALLMENUCOLOR);
m_imageMenu.Add(&bm,(CBitmap*)NULL);
bm.Detach();
// 还有IDB_SMALLMENUDISABLE
m_imageMenuDisable.Create(20, 20, TRUE | ILC_COLOR24, 9, 0);
bm.LoadBitmap(IDB_SMALLMENUDISABLE);
m_imageMenuDisable.Add(&bm,(CBitmap*)NULL);
bm.Detach();
// 还有IDB_SMALLMENUHOT
m_imageMenuHot.Create(20, 20, TRUE | ILC_COLOR24, 9, 0);
bm.LoadBitmap(IDB_SMALLMENUHOT);
m_imageMenuHot.Add(&bm,(CBitmap*)NULL);
bm.Detach();
}
/*
IDB_SMALLMENUCOLOR
IDB_SMALLMENUHOT
IDB_SMALLMENUDISABLE
*/
/////////////////////////////////////////////////////////////////////////////
// 在ManiFram.cpp 中添加初始化菜单图像列表程序
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
// 在CMainFrame::OnCreate中调用菜单图标初始化程序
。。。。。。
InitMenuImage();
。。。。。。
}
/////////////////////////////////////////////////////////////////////////////
HMENU CMainFrame::InitMainFrameMenu()
{
//初始化主菜单
m_menuMainFrame.LoadMenu(IDR_MAINFRAME);
{
// 这只加载图像的一种方法,是一种两步方法,先加载图像列表
m_menuMainFrame.SetImageList(&m_imageMenu);
m_menuMainFrame.SetDisabledImageList(&m_imageMenuDisable);
m_menuMainFrame.SetHotImageList(&m_imageMenuHot);
// 再通过菜单图像索引表为菜单加载图像索引,
m_menuMainFrame.SetImageIndex(nMenuImageIndex,
sizeof(nMenuImageIndex)/sizeof(UINT));
}
// 也可以使用另外一种一步方法加载图像
/*
// 假设MAINFRAM具有m_wndToolBar成员,并且已经设置了真彩位图
// 关于设置工具栏的真彩位图,请参考 http://www.vckbase.com/document/viewdoc/?id=576
// 或者看我的另外一篇文章 《完美实现真彩工具栏》(还没写出来那:))
// 不过源程序里面已经有实现方法了
// 自己看也可以明白的
m_menuMainFrame.LoadToolBar(&m_wndToolBar);
*/
return m_menuMainFrame.Detach();
}
/////////////////////////////////////////////////////////////////////////////
HMENU CMainFrame::InitImageTypeMenu()
{
// 初始化文档模板菜单
m_menuImageType.LoadMenu(IDR_IMAGETYPE);
m_menuImageType.SetImageList(&m_imageMenu);
m_menuImageType.SetDisabledImageList(&m_imageMenuDisable);
m_menuImageType.SetHotImageList(&m_imageMenuHot);
//通过菜单图像索引表为菜单加载图像索引
m_menuImageType.SetImageIndex(nMenuImageIndex,sizeof(nMenuImageIndex)/sizeof(UINT));
return m_menuImageType.Detach();
}
/////////////////////////////////////////////////////////////////////////////
void CMainFrame::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
{
// 记住,顺序一定不能反,因为有些MFC自动添加的菜单是在CMDIFrameWnd::OnInitMenuPopup()
// 中添加的.
// 如果反了,当然就找不到新加入的菜单了
CMDIFrameWnd::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);
// 静态函数,看好了,别忘了写CMenuEx啊
CMenuEx::InitPopupMenu(pPopupMenu, nIndex, bSysMenu);
}
/////////////////////////////////////////////////////////////////////////////
void CMainFrame::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
// 都是她惹的祸"CMDIFrameWnd::OnMeasureItem()",不对子菜单项的尺寸进行测量
// 害的我们只好映射这个函数了
CMDIFrameWnd::OnMeasureItem(nIDCtl, lpMeasureItemStruct);
// 静态函数,看好了,别忘了写CMenuEx啊
CMenuEx::MeasureItem(lpMeasureItemStruct);
} - 在CXXXApp::InitInstance()中添加代码,XXX代表你自己的程序了
BOOL CXXXApp::InitInstance()
{
......
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(
IDR_IMAGETYPE,
RUNTIME_CLASS(CImageDoc),
RUNTIME_CLASS(CChildFrame), // custom MDI child frame
RUNTIME_CLASS(CImageView));
AddDocTemplate(pDocTemplate);
// create main MDI Frame window
CMainFrame* pMainFrame = new CMainFrame;
if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
return FALSE;
m_pMainWnd = pMainFrame;
// 这些才是要添加的代码,别弄错了
// 初始化文档模板菜单
pDocTemplate->m_hMenuShared=pMainFrame->InitImageTypeMenu();
// 初始化主窗体菜单
pMainFrame->m_hMenuDefault=pMainFrame->InitMainFrameMenu();
// 更新,具体干什么没研究,反正不调用就出错了:)
pMainFrame->OnUpdateFrameMenu(pMainFrame->m_hMenuDefault);
// 要添加的代码到这结束
......
}
三、总结
说了这么多,也不知道大家看明白没有,没关系,先贴个图,大家看看效果再说了。
效果图一,使用图像索引表加载的小图标菜单
效果图一,工具条加载的大图标菜单
四、结束语
感谢querw和BCMenu的作者,没有他们的辛勤劳动,后人是没办法站在他们肩膀上的!由于程序写的匆忙,难免有不尽人意和错误的地方,欢迎大家任意修改源程序:) 要说这个菜单做的完美,那是吹牛,世界上哪有完美的东西啊 :) 只要自己觉得完美,就够了。 希望大家能从文章中学到点东西,就好。
更多精彩
赞助商链接