带有图标的自定义绘制菜单,2D-3D 渐变水平/垂直






4.56/5 (9投票s)
2003年11月30日
2分钟阅读

88433

4329
本文描述了一个带有图标的自定义绘制菜单,具有2D-3D渐变水平/垂直效果。
所使用的颜色只是为了突出菜单的功能,可以更改它们。
引言
主要类是 CColorMenu
#define FADE_NONE 0x00 // No 3D Fade #define FADE_HORZ 0x01 // Fade 3D HORZ #define FADE_VERT 0x02 // Fade 3D VERT #define FADE2D_NONE 0x00 // No 2D Fade #define FADE2D_HORZ 0x10 // Fade 2D HORZ #define FADE2D_VERT 0x20 // Fade 2D VERT #define MENU_NONE 0x00 // undefined type of menu #define MENU_SIMPLE 0x01 // normal menu item #define MENU_POPUP 0x02 // pop-up menu item
成员
COLORREF m_Bk2DPop; // Start color (background) at 2D on pop-up menus COLORREF m_Txt2DPop; // Text color at 2D on pop-up menus COLORREF m_Bk2DMen; // Start color (background) at 2D on menus COLORREF m_Txt2DMen; // Text color at 2D on menus COLORREF m_Bk3DPop; // Start color (background) at 3D on pop-up menus COLORREF m_Txt3DPop; // Text color at 3D on pop-up menus COLORREF m_Bk3DMen; // Start color (background) at 3D on menus COLORREF m_Txt3DMen; // Text color at 2D on menus COLORREF m_Fade2DPop; // End color for 2D used at FADE on pop-up menus COLORREF m_Fade3DPop; // End color for 3D used at FADE on pop-up menus COLORREF m_Fade2DMen; // End color for 2D used at FADE on menus COLORREF m_Fade3DMen; // End color for 3D used at FADE on menus protected: // settings of control COLORREF m_ColCheck; // Color of Check COLORREF m_ColSepar; // Color of separator(MF_SEPARATOR) COLORREF m_BkGray; // Color background for Gray value COLORREF m_TxtGray; // Color text for Gray value UINT m_FadeTypeMen; // At 2D FADE for menu start //color m_Bk2DMen TO end //color m_Fade2DMen for menus // At 3D FADE for menu start color //m_Bk3DMen TO end color m_Fade3DMen for menus UINT m_FadeTypePop; // At 2D FADE for menu start //color m_Bk2DPop TO end //color m_Fade2DPop for pop-up menus // At 3D FADE for menu start color //m_Bk3DPop TO end color //m_Fade3DPop for pop-up menus int m_Val3D; // Deep 3D value int m_HeightSep; // Height of separator int m_HeightCel; // Height of a menu item int m_WidthCel; // Width of a menu item VTYPE_ITEMCONT* m_itemsStr; // internal Use VTYPE_MENUCOLOR* m_HandlesMenu; // internal Use
步骤
-
“最近文件”
如果您有“最近文件”,则必须在从
CWinApp
派生的类中使用LoadStdProfileSettingsEx
代替LoadStdProfileSettings
。LoadStdProfileSettingsEx
中使用了一个新的类:从CRecentFileList
派生的CRecentFileListEx
。BOOL CSampleMenuApp::InitInstance() { //................... // Load standard INI file options (including MRU) LoadStdProfileSettingsEx(_AFX_MRU_COUNT); //................... return TRUE; };
如果您没有“最近文件”或
_AFX_MRU_COUNT
= 0,您可以删除CRecentFileListEx
类和void LoadStdProfileSettingsEx(UINT nMaxMRU);
函数。所有这些都用于处理在“最近文件”菜单部分运行时添加的项目。
-
“活动窗口”
如果您使用“活动窗口”,那么处理运行时使用消息
WM_MDISETMENU
插入的项目会比较困难。在每个子框架中,您必须实现
virtual void OnUpdateFrameMenu(BOOL bActive, CWnd* pActivateWnd, HMENU hMenuAlt);
,如下所示void CChildFrame::OnUpdateFrameMenu(BOOL bActivate, CWnd* pActivateWnd, HMENU hMenuAlt) { CMDIChildWnd::OnUpdateFrameMenu(bActivate, pActivateWnd, hMenuAlt); ((CMainFrame*)GetParentFrame())->RefreshInternalMenu(); }
这是
CMDIChildWnd
中的一个虚拟函数,它更新框架菜单,并且您必须通过RefreshInternalMenu
函数告知ColorMenu
“活动窗口”菜单已更改。在
CMainFrame
上,您必须定义RefreshInternalMenu()
,如下所示void CMainFrame::RefreshInternalMenu() { m_IdTimer = SetTimer(INTERNAL_UPDATE_TIMER, 50, NULL); }
并且在定时器函数中,您必须执行以下操作
void CMainFrame::OnTimer(UINT nIDEvent) { if(nIDEvent == INTERNAL_UPDATE_TIMER) { KillTimer(m_IdTimer); m_IdTimer = NULL; HMENU hMenuWindow = GetWindowMenuPopup(GetMenuOfView()); CColorMenu* pMenu = m_menuChildFrame.FindSubMenu(hMenuWindow); if(pMenu) pMenu->RefreshMenusForMDIs(); } CMDIFrameWnd::OnTimer(nIDEvent); }
所有这些都必须使用定时器完成,因为
UpdateFrameMenu
是作为“延迟刷新”进行的。 如果您不使用定时器,您将“看不到新的更新菜单”,您将看到菜单未更改。 -
“最后一步”
在
CMainFrame
上,您必须定义所有菜单:一个用于CMainFrame
,其余用于子框架(如果您有多个)。class CMainFrame : public CMDIFrameWnd { HMENU GetMenuOfView(){return m_menuChildFrame.GetSafeHmenu();} CColorMenu m_menuMainFrame; CColorMenu m_menuChildFrame; }
因此,如果您有多个具有不同菜单的子框架,则必须定义多个
CColorMenu m_menuChildFrame;
在
CMainFrame::OnCreate
中,您只需加载菜单、设置所需的图标并替换默认菜单,如下所示int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; // Load menus m_menuMainFrame.LoadMenu(IDR_MAINFRAME); m_menuChildFrame.LoadMenu(IDR_SAMPLETYPE); // set the icon to items if you want m_menuMainFrame.SetIconToHandle(ID_FILE_NEW, IDI_ICON_NEW); //.................... // replace the default menu HMENU OldMenuDefault = m_hMenuDefault; SetMenu(&m_menuMainFrame); m_hMenuDefault = m_menuMainFrame.GetSafeHmenu(); ::DestroyMenu(OldMenuDefault); // if you set skin please make so: /* CSSkin skin; // ........... m_menuMainFrame.SetSkin(&skin); DrawMenuBar(); */ }
之后,您必须实现
CMainFrame::OnMeasureItem
,如下所示void CMainFrame::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) { if(lpMeasureItemStruct->CtlType == ODT_MENU) { if(m_menuMainFrame.IsMenu((HMENU)lpMeasureItemStruct->itemID)) { m_menuMainFrame.MeasureItem(lpMeasureItemStruct); return; } if(m_menuChildFrame.IsMenu((HMENU)lpMeasureItemStruct->itemID)) { m_menuChildFrame.MeasureItem(lpMeasureItemStruct); return; } //…………………………………… } CMDIFrameWnd::OnMeasureItem(nIDCtl, lpMeasureItemStruct); };
并在
CMainFrame::OnDestroy()
中销毁菜单。void CMainFrame::OnDestroy() { SetMenu(NULL); ::DestroyMenu(m_hMenuDefault); m_hMenuDefault = NULL; m_menuMainFrame.DestroyMenu(); m_menuChildFrame.DestroyMenu(); CMDIFrameWnd::OnDestroy(); }
最后,在每个子框架上,在
CChildFrame::OnCreate
上,替换默认菜单。int CChildFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CMDIChildWnd::OnCreate(lpCreateStruct) == -1) return -1; CMainFrame* pFram = (CMainFrame*)GetParentFrame(); HMENU OldMenuDefault = m_hMenuDefault; m_hMenuDefault = pFram->GetMenuOfView(); m_hMenuShared = m_hMenuDefault; ::DestroyMenu(OldMenuDefault); // if you set skin please make so: /* CSSkin skin; // ........... pFram->m_menuChildFrame.SetSkin(&skin); DrawMenuBar(); */ }
并在销毁时,防止销毁默认菜单。
void CChildFrame::OnDestroy() { m_hMenuShared = NULL; m_hMenuDefault = NULL; CMDIChildWnd::OnDestroy(); }
祝你好运!