VC++的菜单控制和自绘菜单。 (转)

VC++的菜单控制和自绘菜单。 (转)[@more@]菜单控制
为什么即使 调用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);



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

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

首先,使用Re source 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_SY SCOMMAND消息并检测用户菜单的nID参数:

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

{

//Dete Rmine 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:

// Overr ides
 // 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 _DE bug
#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.CreateSoli dbrush (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.Delete object ();
 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 succes sfully ");
 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;
}


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10790690/viewspace-951389/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/10790690/viewspace-951389/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
从VC++项目中的菜单资源建立结构相同的自绘弹出式菜单,原理和步骤如下: (1)CMenu::LoadMenu读入菜单资源; (2)CImageList::Create读入工具栏位图; (3)CMenu::CreatePopupMenu和CMenu::AppendMenu拷贝菜单资源,建立弹出式菜单。其中CMenu::AppendMenu第1个参数设置成MF_OWNERDRAW(自绘), 第四个参数设置成一个附加结构的指针,包括菜单项文字和位图索引等信息。通过这个结构,在自绘制时,可以获取对应的菜单项文字和位图位置索引,其中位图保存在第(2)步中的CImageList变量中; (4)在对右鼠标键的响应函数里,使用CMenu::TrackPopupMenu启动显示弹出式菜单; (5)在弹出式菜单的拥有者窗口(CxxxView)里,处理WM_MEASUREITEM消息和WM_DRAWITEM消息,分别调用CMenuEx::MeasureItem和CMenuEx::DrawItem, 分别用来定义菜单项的尺寸,对菜单项进行自绘; (6)在自绘函数CMenuEx::DrawItem里,通过每个菜单项的附加结构lpDIS->itemData,获得其文字和位图索引,然后分别使用CDC::DrawText和CImageList::Draw,画出该菜单项的文字和位图,从而实现自绘制。 程序在VC6下编译通过。 没有处理的地方:如果菜单项状态是checked或者radio,程序没做处理。另外,弹出式菜单的激活/禁止时,不会自动触发其拥有者窗口的ON_UPDATE_COMMAND_UI宏。不过,可以处理owner窗口的WM_INITMEMUPOPUP消息(在弹出式菜单的每个子菜单弹出时,都会发出此消息),为每个子菜单项单独生成一个CCmdUI对象,调用其CCmdUI::DoUpdate函数,来手动触发ON_UPDATE_COMMAND_UI宏中对应的消息处理函数,使得菜单项能够根据应用环境进行激活和禁止。详见博客: http://oliver.zheng.blog.163.com/blog/static/14241159520143210595266/

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值