在这里提供一个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 windowclass 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/////////////////////////////////////////////////////////////////////////// // // CCustomMenuCCustomMenu::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 stateUINT 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\n", strText); } else { strText.Empty(); hIcon = NULL; }if ( (state & ODS_SELECTED) ) { // draw the down edgesCPen *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\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); //NormalTRACE0 ("SELECT, NORMAL\n"); }// 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\n"); else TRACE0 ("SORRY.NOGO\n"); } //This is needed always so that we can have the space for check s 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\n",strText); pDC->DrawText (strText,rect,DT_LEFT|DT_SINGLELINE|DT_VCENTER); TRACE0("Done\n"); 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; } //*************************************************************************
它可以向你提供以下的功能: 设置字体颜色。
设置高亮度颜色。
设置高亮度时的风格。
设置选中时和在普通状态下的菜单显示的图标。
设置显示图标大小。
在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 windowclass 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///////////////////////////////////////////////////////////////////////////
//
// CCustomMenuCCustomMenu::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 stateUINT 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\n", strText);
}
else
{
strText.Empty();
hIcon = NULL;
}if ( (state & ODS_SELECTED) )
{
// draw the down edgesCPen *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\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); //NormalTRACE0 ("SELECT, NORMAL\n");
}// 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\n");
else
TRACE0 ("SORRY.NOGO\n");
}
//This is needed always so that we can have the space for check s
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\n",strText);
pDC->DrawText (strText,rect,DT_LEFT|DT_SINGLELINE|DT_VCENTER);
TRACE0("Done\n");
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;
}
//*************************************************************************