zoukankan      html  css  js  c++  java
  • VC++的菜单控制和自绘菜单

    菜单控制
    为什么即使调用EnableMenuItem菜单项后,菜单项还处于禁止状态  

    需要将CFrameWnd:: m_bAutomenuEnable设置为FALSE,如果该数据成员为TRUE(缺省值),工作框将自动地禁止没有ON_UPDATE_COMMAND_UI或者ON_COMMAND的菜单项。

    //Disable MFC from automatically disabling menu items.

    m_bAuoMenuEnable=FALSE;

    //Now enable the menu item.

    CMenu* pMenu=GetMenu ();

    ASSERT_VALID (pMenu);

    pMenu->EnableMenuItem (ID_MENU_ITEM,MF_BYCOMMAND | MF_ENABLED);



    如何给系统菜单添加一个菜单项  

    给系统菜单添加一个菜单项需要进行下述三个步骤:

    首先,使用Resource Symbols对话(在View菜单中选择Resource Symbols...

    可以显示该对话)定义菜单项ID,该ID应大于0x0F而小于0xF000;

    其次,调用CWnd::GetSystemMenu获取系统菜单的指针并调用CWnd:: Appendmenu将菜单项添加到菜单中。下例给系统菜单添加两个新的菜单项:

    int CMainFrame:: OnCreate (LPCREATESTRUCT lpCreateStruct)

    {



    //Make sure system menu item is in the right range.

    ASSERT (IDM_MYSYSITEM &0xFFF0)==IDM_MYSYSITEM);

    ASSERT (IDM-MYSYSITEM<0xF000);

    //Get pointer to system menu.

    CMenu* pSysmenu=GetSystemmenu (FALSE);

    ASSERT_VALID (pSysMenu);

    //Add a separator and our menu item to system menu.

    CString StrMenuItem (_T ("New menu item"));

    pSysMenu->Appendmenu (MF_SEPARATOR);

    pSysMenu->AppendMenu (MF_STRING, IDM_MYSYSITEM, strMenuitem);



    }

    现在,选择系统菜单项时用户应进行检测。使用ClassWizard处理

    WM_SYSCOMMAND消息并检测用户菜单的nID参数:

    void CMainFrame:: OnSysCommand (UINT nID,LPARAM lParam)

    {

    //Determine if our system menu item was selected.

    if ( (nID & 0xFFF0)==IDM_MYSYSITEM)

    {

    //TODO-process system menu item

    }

    else

    CMDIFrameWnd:: OnSysCommand (nID, lParam);

    }

    最后,一个设计良好的UI应用程序应当在系统菜单项加亮时在状态条显示一个帮助信息,这可以通过增加一个包含系统菜单基ID的串表的入口来实现。



    如何确定顶层菜单所占据的菜单行数  

    这可以通过简单的减法和除法来实现。首先,用户需要计算主框窗口的高度和客户区;其次,从主框窗口的高度中减去客户区、框边界以及标题的高度;最后,除以菜单栏的高度。下例成员函数是一个计算主框菜单所占据的行数的代码实现。

    int CMainFrame:: GetMenuRows ()

    {

    CRect rcFrame,rcClient;

    GetWindowRect (rcFrame);

    GetClientRect (rcClient);

    return (rcFrame.Height () -rcClient.Height ()-

    :: GetSystemMetrics (SM_CYCAPTION) -

    (:: getSystemMetrics (SM_CYFRAME) *2)) /

    :: GetSystemMetrics (SM_CYMENU);

    }




    自绘菜单
    闻怡洋译 

    在这里提供一个C++类(CCustomMenu),该类是CMenu的子类,并且拥有自绘能力。它可以向你提供以下的功能:

    设置字体颜色。
    设置高亮度颜色。
    设置高亮度时的风格。
    设置选中时和在普通状态下的菜单显示的图标。
    设置显示图标大小。
    在CCustomMenu中定义了结构MENUDATA,你必须根据你的需要填充该结构,并且在增加菜单时提供该结构的指针(调用AppendMenu,InsertMenu)。下面是一个例子:

    1、定义CCustomMenu的实例,和MENUDATA结构变量。

        CCustomMenu m_cCustomMenu;
        MENUDATA menuData [8]; // as many menu items are present , You should be able to use
                    //new and do the same
    2、调用CreateMenu()设置有关参数。
        m_customMenu.CreateMenu ();
        m_customMenu.SetIconSize (25,25); //This is to set the size of the Icon.
                            // This should be used only once for any menu
        // in order to resize it, destroy and create the menu again with different size.
        m_customMenu.SetHighlightStyle (Normal); //Or TextOnly, if you want the
        // background color to remain the same
        // and the Text color to change to the Highlight color.
            // The following setXXXColor sets the menu colors. If you dont want to change any, Dont call these member functions.
         m_customMenu.SetTextColor (RGB (255,0,0));
         m_customMenu.SetBackColor (RGB (255,255,255));
         m_customMenu.SetHighlightColor (RGB (0,0,255));
    3、设置MENUDATA变量,并增加菜单项。
         lstrcpy (menuData[0].menuText , "text1");
         menuData[0].menuIconNormal= IDI_ICON1;
         m_customMenu.AppendMenu (MF_OWNERDRAW,3,(LPCTSTR)menuData);

    3、在你的窗口中重载OnMeasureItem(...)函数。
    void CMyView::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)
    {
        if ( lpMeasureItemStruct->CtlType == ODT_MENU &&
                IsMenu((HMENU)lpMeasureItemStruct->itemID) &&
                (lpMeasureItemStruct->itemID == (UINT)m_hMenuSub) )
        {
            m_customMenu.MeasureItem (lpMeasureItemStruct);
        }
        else
            // let MFC's self-drawing handle it
            CView::OnMeasureItem(nIDCtl, lpMeasureItemStruct);
    }

    下面的函数将帮助你设置菜单属性。

        void SetTextColor (COLORREF );
        void SetBackColor (COLORREF);
        void SetHighlightColor (COLORREF);
        void SetIconSize (int, int);
        void SetHighlightStyle (HIGHLIGHTSTYLE ); // HIGHLIGHTSTYLE : enum {Normal, TextOnly}
        void SetHighlightTextColor (COLORREF);



    下面是文件代码:
    //*************************************************************************
    // CustomMenu.h : header file
    //

    #if
    !defined(AFX_CUSTOMMENU_H__FE5B01C3_1E02_11D1_B87A_0060979CDF6D__INCLUDED_)
    #define AFX_CUSTOMMENU_H__FE5B01C3_1E02_11D1_B87A_0060979CDF6D__INCLUDED_

    #if _MSC_VER >= 1000
    #pragma once
    #endif // _MSC_VER >= 1000
    class MENUDATA
    {
    public:
        MENUDATA () { menuIconNormal = -1; menuIconSelected = -1;};
        char menuText[32];
        UINT menuIconNormal;
        UINT menuIconSelected;
    };

    typedef enum {Normal,TextOnly} HIGHLIGHTSTYLE;

    ////////////////////////////////////////////////
    //
    // CCustomMenu window

    class CCustomMenu : public CMenu
    {
    // Construction
    public:
        CCustomMenu();

    // Attributes
    public:

    // Operations
    public:

    // Overrides
        // ClassWizard generated virtual function overrides
        //{{AFX_VIRTUAL(CCustomMenu)
        //}}AFX_VIRTUAL

    // Implementation
    public:
        virtual ~CCustomMenu();
        virtual void DrawItem( LPDRAWITEMSTRUCT);
        virtual void MeasureItem( LPMEASUREITEMSTRUCT );
        void SetTextColor (COLORREF );
        void SetBackColor (COLORREF);
        void SetHighlightColor (COLORREF);
        void SetIconSize (int, int);
        void SetHighlightStyle (HIGHLIGHTSTYLE );
        void SetHighlightTextColor (COLORREF);

        // Generated message map functions
    protected:
        COLORREF m_crText;
        COLORREF m_clrBack;
        COLORREF m_clrText;
        COLORREF m_clrHilight;
        COLORREF m_clrHilightText;
        LOGFONT m_lf;
        CFont m_fontMenu;
        UINT m_iMenuHeight;
        BOOL m_bLBtnDown;
        CBrush m_brBackground,m_brSelect;
        CPen m_penBack;
        int m_iconX,m_iconY;
        HIGHLIGHTSTYLE m_hilightStyle;

        //{{AFX_MSG(CCustomMenu)
            // NOTE - the ClassWizard will add and remove member functions here.
        //}}AFX_MSG
    };

    ///////////////////////////////////////
    //

    //{{AFX_INSERT_LOCATION}}
    // Microsoft Developer Studio will insert additional declarations immediately before the previous line.

    #endif //!defined(AFX_CUSTOMMENU_H__FE5B01C3_1E02_11D1_B87A_0060979CDF6D__INCLUDED_)

    //*************************************************************************
    // CustomMenu.cpp : implementation file
    //

    #include "stdafx.h"
    #include "CustomMenu.h"

    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif

    ////////////////////////////////////////////////
    //
    // CCustomMenu

    CCustomMenu::CCustomMenu()
    {
        m_clrText = GetSysColor (COLOR_MENUTEXT);
        m_clrBack = GetSysColor (COLOR_MENU);
        m_brBackground.CreateSolidBrush (m_clrBack);
        m_penBack.CreatePen (PS_SOLID,0,m_clrBack);
        m_crText = m_clrText;
        m_bLBtnDown = FALSE;
        m_iconX = GetSystemMetrics ( SM_CXMENUCHECK);
        m_iconY = GetSystemMetrics (SM_CYMENUCHECK );

        m_clrHilight = GetSysColor (COLOR_HIGHLIGHT);
        m_brSelect.CreateSolidBrush (m_clrHilight);
        m_clrHilightText = GetSysColor (COLOR_HIGHLIGHTTEXT);

        ZeroMemory ((PVOID) &m_lf,sizeof (LOGFONT));
        NONCLIENTMETRICS nm;
        nm.cbSize = sizeof (NONCLIENTMETRICS);

        //Get the system metrics for the Captionfromhere
        VERIFY (SystemParametersInfo (SPI_GETNONCLIENTMETRICS,0,&nm,0));

        m_lf = nm.lfMenuFont;
        m_iMenuHeight = nm.iMenuHeight;
        m_fontMenu.CreateFontIndirect (&m_lf);
    }

    CCustomMenu::~CCustomMenu()
    {
        if ((HBRUSH) m_brBackground != NULL)
            m_brBackground.DeleteObject ();
        if ((HFONT)m_fontMenu !=NULL)
            m_fontMenu.DeleteObject ();
        if ((HBRUSH)m_brSelect != NULL)
             m_brSelect.DeleteObject ();
    }



    ////////////////////////////////////////////////
    //
    // CCustomMenu message handlers


    void CCustomMenu::DrawItem (LPDRAWITEMSTRUCT lpDIS)
    {
        ASSERT(lpDIS != NULL);

        CDC* pDC = CDC::FromHandle(lpDIS->hDC);
        CRect rect;
        HICON hIcon;
        COLORREF crText = m_crText;
        // draw the colored rectangle portion
        rect.CopyRect(&lpDIS->rcItem);

        // draw the up/down/focused/disabled state

        UINT action = lpDIS->itemAction;
        UINT state = lpDIS->itemState;
        CString strText;
        LOGFONT lf;
        lf = m_lf;

        CFont dispFont;
        CFont *pFont;
        //GetWindowText(strText);
        if (lpDIS->itemData != NULL)
        {
            strText = (((MENUDATA*) (lpDIS->itemData))->menuText);
            if ((((MENUDATA *)(lpDIS->itemData))->menuIconNormal) == -1)
                hIcon = NULL;
            else if (state & ODS_SELECTED)
            {
                if ((((MENUDATA *)(lpDIS->itemData))->menuIconSelected) != -1)
                    hIcon = AfxGetApp ()->LoadIcon (((MENUDATA *)(lpDIS->itemData))->menuIconSelected);
                else
                    hIcon = AfxGetApp()->LoadIcon (((MENUDATA*)(lpDIS->itemData))->menuIconNormal);
            }
            else
                hIcon = AfxGetApp()->LoadIcon (((MENUDATA*)(lpDIS->itemData))->menuIconNormal);

            TRACE1 ("Draw for %s ", strText);
        }
        else
        {
            strText.Empty();
            hIcon = NULL;
        }

        if ( (state & ODS_SELECTED) )
        {
            // draw the down edges

            CPen *pOldPen = pDC->SelectObject (&m_penBack);

            //You need only Text highlight and thats what you get
            if (m_hilightStyle != Normal)
            {
                pDC->FillRect (rect,&m_brBackground);
            }
            else
            {
                pDC->FillRect (rect,&m_brSelect);
            }

            pDC->SelectObject (pOldPen);
            pDC->Draw3dRect (rect,GetSysColor (COLOR_3DHILIGHT),GetSysColor(COLOR_3DSHADOW));
            lf.lfWeight = FW_BOLD;
            if ((HFONT)dispFont != NULL)
                dispFont.DeleteObject ();
            dispFont.CreateFontIndirect (&lf);
            crText = m_clrHilightText;

            //While selected move the text a bit
            TRACE0 ("SELECT,SELECTED ");
        }
        else
        {
            CPen *pOldPen = pDC->SelectObject (&m_penBack);
            pDC->FillRect (rect,&m_brBackground);
            pDC->SelectObject (pOldPen);
            // draw the up edges
            pDC->Draw3dRect (rect,m_clrBack,m_clrBack);
            if ((HFONT)dispFont != NULL)
                dispFont.DeleteObject ();
            dispFont.CreateFontIndirect (&lf); //Normal

            TRACE0 ("SELECT, NORMAL ");
        }

        // draw the text if there is any
        //We have to paint the text only if the image is nonexistant
        if (hIcon != NULL)
        {
            if(DrawIconEx (pDC->GetSafeHdc(),rect.left,rect.top,hIcon,
                (m_iconX)?m_iconX:32,(m_iconY)?m_iconY:32,0,NULL,DI_NORMAL))
                TRACE0("Wrote the icon successfully ");
            else
                TRACE0 ("SORRY.NOGO ");
        }
        //This is needed always so that we can have the space for check marks
        rect.left = rect.left +((m_iconX)?m_iconX:32);

        if ( !strText.IsEmpty())
        {
            // pFont->GetLogFont (&lf);

            int iOldMode = pDC->GetBkMode();

            pDC->SetBkMode( TRANSPARENT);

            pDC->SetTextColor( crText);

            pFont = pDC->SelectObject (&dispFont);
            TRACE1( "About To DrawText %s ",strText);
            pDC->DrawText (strText,rect,DT_LEFT|DT_SINGLELINE|DT_VCENTER);
            TRACE0("Done ");
            pDC->SetBkMode( iOldMode );
            pDC->SelectObject (pFont); //set it to the old font
        }
        dispFont.DeleteObject ();
    }

    void CCustomMenu::MeasureItem( LPMEASUREITEMSTRUCT lpMIS )
    {
        CDC *pDC = AfxGetApp()->m_pMainWnd->GetDC();
        CFont* pFont = pDC->SelectObject (&m_fontMenu);
        int iconX = 0,iconY= 0;
        TEXTMETRIC tm;
        pDC->GetTextMetrics (&tm);
        pDC->SelectObject (pFont);
        AfxGetApp()->m_pMainWnd->ReleaseDC (pDC);

        if (m_iconX)
            iconX = m_iconX;
        if (m_iconY)
            iconY = m_iconY;

        lpMIS->itemWidth = iconX + tm.tmAveCharWidth * lstrlen(((MENUDATA*)(lpMIS->itemData))->menuText) +10;
        lpMIS->itemHeight = (iconY > (m_iMenuHeight+1))?iconY:m_iMenuHeight + 1;
    }

    void CCustomMenu::SetIconSize (int width, int height)
    {
        m_iconX = width;
        m_iconY = height;
    }

    void CCustomMenu::SetTextColor (COLORREF clrText)
    {
        m_crText = clrText;
    }

    void CCustomMenu::SetBackColor (COLORREF clrBack)
    {
        m_clrBack = clrBack;
        if ((HBRUSH)m_brBackground != NULL)
            m_brBackground.DeleteObject ();
        m_brBackground.CreateSolidBrush (clrBack);
    }

    void CCustomMenu::SetHighlightColor (COLORREF clrHilight)
    {
        m_clrHilight = clrHilight;
        if ((HBRUSH)m_brSelect != NULL)
                m_brSelect.DeleteObject ();
        m_brSelect.CreateSolidBrush (clrHilight);
    }

    void CCustomMenu::SetHighlightTextColor (COLORREF clrHilightText)
    {
        m_clrHilightText = clrHilightText;
    }


    void CCustomMenu::SetHighlightStyle (HIGHLIGHTSTYLE hilightStyle)
    {
        m_hilightStyle = hilightStyle;
    }

  • 相关阅读:
    Dubbo架构设计及原理详解
    Zookeeper+Dubbo+SpringMVC环境搭建
    Java 延迟队列使用
    深入理解Spring Redis的使用 (九)、通过Redis 实现 分布式锁 的 BUG,以及和数据库加锁的性能测试
    深入理解Spring Redis的使用 (八)、Spring Redis实现 注解 自动缓存
    深入理解Spring Redis的使用 (七)、Spring Redis 使用 jackson序列化 以及 BaseDao代码
    深入理解Spring Redis的使用 (六)、用Spring Aop 实现注解Dao层的自动Spring Redis缓存
    深入理解Spring Redis的使用 (五)、常见问题汇总
    深入理解Spring Redis的使用 (四)、RedisTemplate执行Redis脚本
    深入理解Spring Redis的使用 (三)、使用RedisTemplate的操作类访问Redis
  • 原文地址:https://www.cnblogs.com/liangxiaofeng/p/4383219.html
Copyright © 2011-2022 走看看