自绘菜单

原创 2007年10月13日 17:13:00



 


在这里提供一个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 "testdll.h"
#include "CustomMenu.h"

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

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CCustomMenu::CCustomMenu()
{
    m_clrText = GetSysColor (COLOR_MENUTEXT);
    m_clrBack = GetSysColor (COLOR_MENU);

    m_brBackground.CreateSolidBrush (m_clrBack);
    m_penBack.CreatePen (PS_SOLID,1,RGB(0,0,255));
    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 hNormalIcon;
 HICON hLightIcon;
    COLORREF crText = m_crText;
    // draw the colored rectangle portion

    rect.CopyRect(&lpDIS->rcItem);

 CRect originRect;
 originRect.CopyRect(&lpDIS->rcItem);
 //rect.left=rect.left+3;
 //rect.top=rect.top+3;
    // 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)
  {  
   hNormalIcon = NULL;
   hLightIcon=NULL;
  }
        else if (state & ODS_SELECTED)
        {
            if ((((MENUDATA *)(lpDIS->itemData))->menuIconSelected) != -1)
   {
                hNormalIcon = AfxGetApp ()->LoadIcon (((MENUDATA *)(lpDIS->itemData))->menuIconSelected);
    hLightIcon=AfxGetApp ()->LoadIcon (((MENUDATA *)(lpDIS->itemData))->menuIconSelected);
   }
   else
   {
                hNormalIcon = AfxGetApp()->LoadIcon (((MENUDATA*)(lpDIS->itemData))->menuIconNormal);
    hLightIcon=AfxGetApp()->LoadIcon (((MENUDATA*)(lpDIS->itemData))->menuIconSelected);
   }
  }
        else
  {
            hNormalIcon = AfxGetApp()->LoadIcon (((MENUDATA*)(lpDIS->itemData))->menuIconNormal);
   hLightIcon =AfxGetApp()->LoadIcon (((MENUDATA*)(lpDIS->itemData))->menuIconSelected);
   TRACE1 ("Draw for %s/n", strText);
  }
    }
    else
    {
        strText.Empty();
        hNormalIcon = NULL;
  hLightIcon=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
  //originRect.left=originRect.left+3;
  //originRect.top=originRect.top+3;
  //originRect.right=originRect.right-2;
  //originRect.bottom=originRect.bottom-2;

  
        if (m_hilightStyle != Normal)
        {
            pDC->FillRect (rect,&m_brBackground);//brnull
        }
        else
        {
            pDC->FillRect (rect,&m_brSelect);//brnull
        }

  pDC->Draw3dRect (rect,GetSysColor (COLOR_3DHILIGHT),GetSysColor(COLOR_3DSHADOW));
  CBrush *brnull=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
  pDC->SelectObject(brnull);
        pDC->Rectangle(originRect);
       
        pDC->SelectObject (pOldPen);
  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/n");
        if(DrawIconEx (pDC->GetSafeHdc(),rect.left,rect.top,hLightIcon,
            (m_iconX)?m_iconX:32,(m_iconY)?m_iconY:32,0,NULL,DI_NORMAL))//m_brSelectm_brBackground
            TRACE0("Wrote the icon successfully/n");
 }
    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/n");
        if(DrawIconEx (pDC->GetSafeHdc(),rect.left,rect.top,hNormalIcon,
            (m_iconX)?m_iconX:32,(m_iconY)?m_iconY:32,0,NULL,DI_NORMAL))//m_brSelectm_brBackground
            TRACE0("Wrote the icon successfully/n");  
 }
 /*
    if ((hNormalIcon != NULL) && (state & ODS_SELECTED))
    {
        if(DrawIconEx (pDC->GetSafeHdc(),rect.left,rect.top,hNormalIcon,
            (m_iconX)?m_iconX:32,(m_iconY)?m_iconY:32,0,NULL,DI_NORMAL))//m_brSelectm_brBackground
            TRACE0("Wrote the icon successfully/n");
        else
            TRACE0 ("SORRY.NOGO/n");
    }

 else
 {
        if(DrawIconEx (pDC->GetSafeHdc(),rect.left,rect.top,hLightIcon,
            (m_iconX)?m_iconX:32,(m_iconY)?m_iconY:32,0,NULL,DI_NORMAL))//m_brSelectm_brBackground
            TRACE0("Wrote the icon successfully/n");
        else
            TRACE0 ("SORRY.NOGO/n");
 }
 */
    // draw the text if there is any
    //We have to paint the text only if the image is nonexistant

    //This is needed always so that we can have the space for check marks
 
    rect.left = rect.left +((m_iconX)?m_iconX:32)+5;
 
    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/n",strText);
        pDC->DrawText (strText,rect,DT_LEFT|DT_SINGLELINE|DT_VCENTER);
        TRACE0("Done/n");
        pDC->SetBkMode( iOldMode );
  

  //CBrush *brnull=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
  //pDC->FillRect(&originRect,brnull);
        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;
}
 

// CustomMenu.cpp: implementation of the CCustomMenu class.
//
//////////////////////////////////////////////////////////////////////

MFC 菜单自绘

背景:由于项目要求将现有MFC MDI框架的程序作一次界面优化,首要的就是系统菜单的优化。具体要求有菜单项尺寸、菜单背景色,菜单栏背景色等。工作期间深刻体会到了MFC做界面的痛苦,这里把这期间所使用到...
  • u010679316
  • u010679316
  • 2016年06月16日 20:52
  • 1942

MFC小练手:详解自绘右键菜单(继承CMenu)

也许女生被人感觉审美观会好点,所以第一个任务就是设计一个菜单。   而我的审美观觉得我做的东西都不会很colorful,因为我是个素色主义者,平日里穿的衣服裙子都是黑白灰红的深女风。(咳跑题了) ...
  • ennika
  • ennika
  • 2015年08月21日 09:09
  • 3036

MFC 单文档标题栏菜单按钮重绘

1、在MainFrame中实现 OnMeasureItem和OnDrawItem函数 void CMainFrame::OnMeasureItem( int nIDCtl, LPMEASUREITEM...
  • lijie0073237
  • lijie0073237
  • 2016年03月30日 15:41
  • 656

Qt重绘标题栏

#ifndef FRAME_H#define FRAME_H #include class QToolButton; class CustomFrame : public QFrame { ...
  • liuyanfeier
  • liuyanfeier
  • 2016年10月06日 13:22
  • 581

C# wndproc 重绘windows窗体标题栏和边框

C#重绘windows窗体标题栏和边框 摘要 windows桌面应用程序都有标准的标题栏和边框,大部分程序也默认使用这些样式,一些对视觉效果要求较高的程序,如QQ,  MSN,迅雷等聊天工具的样式...
  • truelove12358
  • truelove12358
  • 2013年12月24日 22:19
  • 1997

MFC 菜单自绘

一、要想自绘菜单,首要的就是子类化菜单类,拥有自己的自定义菜单类。 也有大神子类化CWnd。。。这应该属于高度定制了,表示驾驭不了,还是看子类化的吧。 关于自绘菜单类很多大神有分享,由于自己水平...
  • season1201
  • season1201
  • 2016年11月28日 16:14
  • 662

怎样在去掉自绘菜单的边框

菜单其实也是一种窗口,是类名为“#32768”的窗口,我们可以通过钩子截取窗口过程,对相应的消息进行处理,需要注意的是,菜单窗口不是通过WM_PAINT和WM_NCPAINT对窗口进行绘制,而是通过W...
  • aa1991
  • aa1991
  • 2013年08月08日 22:38
  • 613

全功能的自绘菜单BCmenu类

翻译来源:https://www.codeproject.com/Articles/22/Cool-Owner-Drawn-Menus-with-Bitmaps-Version 这个类很常见,在很多源...
  • greless
  • greless
  • 2017年06月13日 20:08
  • 160

自绘菜单的实现 ----------原作者querw

在VCKBASE上读到《一种漂亮的自绘菜单》 [作者:郑恒 (lbird)]。应用到我的工程里后发现:文章中提到的效果能很好的实现。但是有一点不方便:需要映射 WM_DRAWITEM 和 WM_MEA...
  • gh2663287
  • gh2663287
  • 2015年09月15日 21:55
  • 589

一种革命性的自绘菜单实现

简介  自从发布了第一个版本的Windows   API后,改变(美化完善)通过Windows   GUI实现的界面元素的缺省外观这一举措,是Windows程序员所面临的一个永不停息的挑战。任何...
  • wishfly
  • wishfly
  • 2014年11月13日 16:53
  • 1054
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:自绘菜单
举报原因:
原因补充:

(最多只允许输入30个字)