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\n",
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\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");
}
// 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
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\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;
}