65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.56/5 (9投票s)

2003年11月30日

2分钟阅读

viewsIcon

88433

downloadIcon

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

步骤

  1. “最近文件”

    如果您有“最近文件”,则必须在从 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); 函数。

    所有这些都用于处理在“最近文件”菜单部分运行时添加的项目。

  2. “活动窗口”

    如果您使用“活动窗口”,那么处理运行时使用消息 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 是作为“延迟刷新”进行的。 如果您不使用定时器,您将“看不到新的更新菜单”,您将看到菜单未更改。

  3. “最后一步”

    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();
    }

    祝你好运!

© . All rights reserved.