自绘菜单的实现

自绘菜单的实现

闻怡洋译

在这里提供一个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;
}
//*************************************************************************

posted @ 2012-11-28 15:02  盗草人  阅读(307)  评论(0)    收藏  举报