分享

用MFC创建菜单按钮(转)

 筱肆 2014-06-08

用MFC创建菜单按钮(转)  

2010-04-27 17:24:02|  分类: C/C++ |举报 |字号 订阅

 

用MFC创建菜单按钮

现在有不少的软件都有这样的一种界面效果:当用户单击某一个按钮之后,并不是简单地执行某种功能或弹出一个对话框,而是在按钮旁边弹出一个菜单,让用户作更详细地选择,这在某种程度上就代替了简单的对话框,而且较对话框更为“用户友好”。这样的按钮基本上有两种类型:在按钮上显示文字的和在按钮上显示箭头的,显示箭头常见的有向右的和向下的两种,还有向上的和向左的。图示为常见的风格,即向下的箭头和在按钮左下角弹出菜单。那么,我们在编程时如何实现这一功能呢?

用MFC创建菜单按钮(转) - 金星 - 金清。。。我们知道,MFC中的CButton类有一个虚函数名叫DrawItem(),若在对话框模板中为控件指定了BS_OWNERDRAW风格,则在运行时将调用这个函数来画按钮,而CMenu类的成员函数TrackPopupMenu()则可以在屏幕的任何位置弹出菜单。由上得到启发,只要我们合理地使用这两个函数,就能创建出“菜单按钮”来。

下面的CMenuButton类封装了全部的这些功能,让我们先来看一下它的制作原理。

用MFC创建菜单按钮(转) - 金星 - 金清。。。在取得了按钮的矩形区域之后,取其一个角落的值传递给TrackPopupMenu()函数即可实现弹出菜单,在TrackPopupMenu内部使用TPM_RETURNCMD标志可以得到用户选择的菜单的命令ID,以供进一步的处理;在重载了DrawItem()函数之后,我们可以在函数的内部使用CDC::DrawFrameControl()函数来画出基本的按钮外观,再在中间部位画一个箭头即可。箭头可以用Marlett字体来画。也许有人会担心,若果其他人的机器没装Marlett字体怎么办?其实,任何一台安装Windows的机器离开了Marlett字体都无法正常工作,先请看下图,这是Windows“系统工具”中自带的“字符映射表”。

看到最上面一行中的那几个箭头了吗?就是要把它们画在按钮上。等一等,另外的几个符号怎么也那么熟悉?这不就是几乎每个窗口上都有的“最小化”、“还原”、“关闭”和“最大化”按钮吗?不错,Windows正是使用这几个字符在标题栏上绘图的。其实,Windows中的最“标准”的画箭头的方法就是使用Marlett字体,无论是工具栏上的箭头还是组合框中的箭头,都是这样画出的。有时,在乱删了字体之后,组合框或工具栏的下拉箭头会变成数字6或者9,为什么?看到状态栏上的“击键值”了吗?——“6”,往右数,那个小一点的下箭头正好是——“9”。

下面是具体的制作过程。

首先,生成一个MFC AppWizard EXE 工程,最好是基于对话框的工程,当然,利用现有的工程也可以。

生成一个以CButton为基类的新类,名为CMenuButton,然后用ClassWizard为其添加两个成员函数:DrawItem()和PreSubclassWidnow();手工为CMenuButton类添加BOOL类型m_bDrawFocusRect成员变量,用于决定是否在按钮上画焦点矩形,添加SetDrawFocusRect()函数用于设置这个标志,默认为画焦点矩形;添加两个枚举类型的变量m_ArrowType和m_PopupPos,用于决定所画的箭头的类型和菜单弹出的位置。箭头可为右箭头、下箭头、小右箭头、小下箭头、上箭头和左箭头(参见本文开始处的图);菜单的弹出位置可以为按钮的左上角、右上角、左下角和右下角。最后手工添加两个函数,SetArrowType()和SetMenuPopupPos(),用于设置以上各种风格,其默值分别为画右箭头和在左下角弹出。

如果只需要菜单而不需要画箭头,只需置空BS_OWNERDRAW标志位即可,添加一个SetStyle()函数,用于设置是画箭头还是显示文本,其默认值是画箭头。

为方便处理按钮的BN_CLICKED通知消息,为CMenuButton类创建一个公有的成员函数OnClick(),以便在BN_CLICKED的消息处理器中调用。它有两个参数,第一个是菜单资源的ID,第二个参数为子菜单的ID,默认为0。如果只有一组子菜单,则可使用其默认值0。OnClick()函数的返回值为所选的菜单项的命令ID,若未作任何有效选择,则返回0。

下面是程序代码。

头文件:

#if !defined(_EWAY_MEMUBUTTON_H__INCLUDED_)

#define _EWAY_MEMUBUTTON_H__INCLUDED_

#if _MSC_VER >= 1000

#pragma once

#endif // _MSC_VER >= 1000

// MenuButton.h : header file

//

class CMenuButton : public CButton

{

public:

CMenuButton();

virtual ~CMenuButton();

DECLARE_DYNAMIC( CMenuButton )

enum ArrowType

{

arrowRight,//向右的箭头;

arrowDown, //向下的箭头;

arrowSmallRight, //向右的小箭头;

arrowSmallDown, //向下的小箭头;

arrowUp, //向上的箭头;

arrowLeft//向左的箭头;

}m_ArrowType;

enum PopupPos

{

//名称为TopLeft等等,遵守英文习惯;

posTopLeft, //左上角;

posBottomLeft, //左下角;

posTopRight, //右上角;

posBottomRight, //右下角;

}m_PopupPos;

virtual UINT OnClick(UINT nIDMenuResource,UINT nSubMenu=0);

void SetArrowType(CMenuButton::ArrowType type=CMenuButton::arrowRight);

void SetDrawFocusRect(BOOL bDrawFocusRect=TRUE);

void SetMenuPopupPos(CMenuButton::PopupPos pos=CMenuButton::posBottomLeft);

void SetStyle(BOOL bDrawArrow=TRUE);

// Overrides

// ClassWizard generated virtual function overrides

//{{AFX_VIRTUAL(CMenuButton)

public:

virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);

protected:

virtual void PreSubclassWindow();

//}}AFX_VIRTUAL

protected:

BOOL m_bDrawFocusRect;

//{{AFX_MSG(CMenuButton)

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

//{{AFX_INSERT_LOCATION}}

// Microsoft Developer Studio will insert additional declarations immediately before the previous line.

#endif // !defined(_EWAY_MEMUBUTTON_H__INCLUDED_)

实现文件:

// MenuButton.cpp : implementation file

//

#include "stdafx.h"

#include "MenuButtonTest.h"

#include "MenuButton.h"

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

/////////////////////////////////////////////////////////////////////////////

// CMenuButton

IMPLEMENT_DYNAMIC( CMenuButton, CButton )

CMenuButton::CMenuButton()

{

SetArrowType();

SetDrawFocusRect();

SetMenuPopupPos();

}

CMenuButton::~CMenuButton()

{

}

 

BEGIN_MESSAGE_MAP(CMenuButton, CButton)

//{{AFX_MSG_MAP(CMenuButton)

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////

// CMenuButton message handlers

void CMenuButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)

{

//使用FromeHandle()创建临时的对象,若使用Attach()则必需在最后使用Detach()

CDC *pDC= CDC::FromHandle(lpDrawItemStruct->hDC);

//得到画笔的颜色;

CPen pen;

if( (lpDrawItemStruct->itemState&ODS_DISABLED) )

{

pen.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_GRAYTEXT) );

}

else

{

pen.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_BTNTEXT) );

}

CPen * pOldPen = pDC->SelectObject(&pen);

CFont font;

font.CreateFont(12, 0, 0, 0, FW_NORMAL, 0, 0, 0,

DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,

CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,

DEFAULT_PITCH|FF_SWISS, "Marlett");

CFont * pOldFont=pDC->SelectObject(&font);

CSize size=pDC->GetTextExtent("4",1);

//决定箭头的样子,具体的值可在“字符映射表”中查得;

CString strArrow;

switch (m_ArrowType)

{

case CMenuButton::arrowRight:

strArrow="4";

break;

case CMenuButton::arrowDown:

strArrow="6";

break;

case CMenuButton::arrowSmallRight:

strArrow="8";

break;

case CMenuButton::arrowSmallDown:

strArrow="9";

break;

case CMenuButton::arrowUp:

strArrow="5";

break;

case CMenuButton::arrowLeft:

strArrow="3";

break;

default:

ASSERT(FALSE);

}

//计算座标值,用于绘制箭头;

int x=(lpDrawItemStruct->rcItem.right-lpDrawItemStruct->rcItem.left-size.cx)/2;

int y=(lpDrawItemStruct->rcItem.bottom-lpDrawItemStruct->rcItem.top-size.cy)/2;

//画按钮与箭头;

if( (lpDrawItemStruct->itemState&ODS_SELECTED) )

{

pDC->DrawFrameControl(&lpDrawItemStruct->rcItem, DFC_BUTTON, DFCS_BUTTONPUSH|DFCS_PUSHED);

//在按钮被按下时,上面的字符要有一个向右和向下的偏移;

pDC->TextOut(++x,++y,strArrow);

}

else

{

pDC->DrawFrameControl(&lpDrawItemStruct->rcItem, DFC_BUTTON, DFCS_BUTTONPUSH);

pDC->TextOut(x,y,strArrow);

}

//如果需要,画焦点矩形;

if( (lpDrawItemStruct->itemState&ODS_FOCUS) && m_bDrawFocusRect)

{

CRect rectFocus(lpDrawItemStruct->rcItem);

rectFocus.DeflateRect(3,3); //看起来比较接近的值;

pDC->DrawFocusRect(rectFocus);

}

//仅将对象选回即可,不必调用DeleteTempMap();

pDC->SelectObject(pOldPen);

pDC->SelectObject(pOldFont);

}

UINT CMenuButton::OnClick(UINT nIDMenuResource, UINT nSubMenu/*=0*/)

{

CMenu menu;

//装载菜单;

VERIFY(menu.LoadMenu(nIDMenuResource) );

//得到子菜单;

CMenu *pPopup = menu.GetSubMenu(nSubMenu);//默认为第一组子菜单;

ASSERT(pPopup != NULL);

CRect rect;

GetWindowRect(rect);

POINT point;

//决定弹出菜单的位置;

switch (m_PopupPos)

{

case CMenuButton::posTopLeft://左上角;

point.x=rect.left;

point.y=rect.top;

break;

case CMenuButton::posBottomLeft://左下角;

point.x=rect.left;

point.y=rect.bottom;

break;

case CMenuButton::posTopRight://右上角;

point.x=rect.right;

point.y=rect.top;

break;

case CMenuButton::posBottomRight://右下角;

point.x=rect.right;

point.y=rect.bottom;

break;

default:

ASSERT(FALSE);

}

//弹出菜单;

UINT nMenuSel = pPopup->TrackPopupMenu((TPM_LEFTALIGN|TPM_LEFTBUTTON |TPM_NONOTIFY |TPM_RETURNCMD),point.x, point.y, this);

pPopup->DestroyMenu();

//返回被选择的菜单的ID,如果无任何有效的选择,将返回0;

return nMenuSel;

}

void CMenuButton::PreSubclassWindow()

{

CButton::PreSubclassWindow();

//默认值:加入BS_OWNERDRAW风格;

ModifyStyle(0,BS_OWNERDRAW);

}

void CMenuButton::SetArrowType(CMenuButton::ArrowType type)

{

m_ArrowType=type;

}

void CMenuButton::SetDrawFocusRect(BOOL bDrawFocusRect)

{

m_bDrawFocusRect=bDrawFocusRect;

}

void CMenuButton::SetMenuPopupPos(CMenuButton::PopupPos pos)

{

m_PopupPos=pos;

}

void CMenuButton::SetStyle(BOOL bDrawArrow)

{

if(bDrawArrow)

{

ModifyStyle(0,BS_OWNERDRAW,SWP_NOMOVE|SWP_NOZORDER| SWP_NOSIZE);

}

else

{

ModifyStyle(BS_OWNERDRAW,0,SWP_NOMOVE|SWP_NOZORDER| SWP_NOSIZE);

}

}

要使用这个类,为对话框添加CMenuButton类型的按钮成员变量,若需改变默认风格,则可在OnInitDialog中调用CMenuButton类的公有成员函数SetArrowType()、SetDrawFocusRect()、SetMenuPopupPos()或SetStyle(),在ClassWizard中为对话框添加按钮的BN_CLICKED消息处理函数,然后在其中调用CMenuButton类的OnClick()成员函数,并指定一个菜单ID给它,最后处理OnClick()函数的返回值即可。下面是一个例子。

void CMenuButtonTestDlg::OnTest()

{

UINT nSel=m_btnTest.OnClick(IDR_POPUP);

switch(nSel)

{

case ID_APP_EXIT:

SendMessage(WM_CLOSE,0,0);

break;

case ID_POPUP_ITEM1:

AfxMessageBox("您选择了第一项!");

break;

case ID_POPUP_ITEM2:

AfxMessageBox("您选择了第二项!");

break;

case ID_POPUP_ITEM3:

AfxMessageBox("您选择了第三项!");

break;

default:

//Do nothing;

;

}

}

所用菜单的资源描述如下,外观可参见文首的图。

IDR_POPUP MENU DISCARDABLE

BEGIN

POPUP "_POPUP_"

BEGIN

MENUITEM "第一项", ID_POPUP_ITEM1

MENUITEM "第二项", ID_POPUP_ITEM2

MENUITEM "第三项", ID_POPUP_ITEM3

MENUITEM SEPARATOR

MENUITEM "退出(&X)", ID_APP_EXIT

END

END

BOOL CMenuButtonTestDlg::OnInitDialog()

{

CDialog::OnInitDialog();

//因为这几个值都是默认值,所以注释掉,仅为了演示用法;

//m_btnTest.SetDrawFocusRect(TRUE);

//m_btnTest.ArrowType (CMenuButton::arrowRight);

//m_btnTest.SetStyle(TRUE);

//m_btnTest.SetMenuPopupPos(CMenuButton::posBottomLeft);

return TRUE;

}

值得补充说明的是,使用CMenuButton类的时候,并不一定需要在对话框模板中为按钮指定BS_OWNERDRAW风格,因为在缺省情况下,CMenuButton类的PreSubclassWindow()函数中已经自动加入了这一风格。

 

http://www./article/buttonctrl/1.htm

阅读(283)| 评论(0)
|      
喜欢 推荐 转载

最近读者

用MFC创建菜单按钮(转)  

2010-04-27 17:24:02|  分类: C/C++ |举报 |字号 订阅

 

用MFC创建菜单按钮

现在有不少的软件都有这样的一种界面效果:当用户单击某一个按钮之后,并不是简单地执行某种功能或弹出一个对话框,而是在按钮旁边弹出一个菜单,让用户作更详细地选择,这在某种程度上就代替了简单的对话框,而且较对话框更为“用户友好”。这样的按钮基本上有两种类型:在按钮上显示文字的和在按钮上显示箭头的,显示箭头常见的有向右的和向下的两种,还有向上的和向左的。图示为常见的风格,即向下的箭头和在按钮左下角弹出菜单。那么,我们在编程时如何实现这一功能呢?

用MFC创建菜单按钮(转) - 金星 - 金清。。。我们知道,MFC中的CButton类有一个虚函数名叫DrawItem(),若在对话框模板中为控件指定了BS_OWNERDRAW风格,则在运行时将调用这个函数来画按钮,而CMenu类的成员函数TrackPopupMenu()则可以在屏幕的任何位置弹出菜单。由上得到启发,只要我们合理地使用这两个函数,就能创建出“菜单按钮”来。

下面的CMenuButton类封装了全部的这些功能,让我们先来看一下它的制作原理。

用MFC创建菜单按钮(转) - 金星 - 金清。。。在取得了按钮的矩形区域之后,取其一个角落的值传递给TrackPopupMenu()函数即可实现弹出菜单,在TrackPopupMenu内部使用TPM_RETURNCMD标志可以得到用户选择的菜单的命令ID,以供进一步的处理;在重载了DrawItem()函数之后,我们可以在函数的内部使用CDC::DrawFrameControl()函数来画出基本的按钮外观,再在中间部位画一个箭头即可。箭头可以用Marlett字体来画。也许有人会担心,若果其他人的机器没装Marlett字体怎么办?其实,任何一台安装Windows的机器离开了Marlett字体都无法正常工作,先请看下图,这是Windows“系统工具”中自带的“字符映射表”。

看到最上面一行中的那几个箭头了吗?就是要把它们画在按钮上。等一等,另外的几个符号怎么也那么熟悉?这不就是几乎每个窗口上都有的“最小化”、“还原”、“关闭”和“最大化”按钮吗?不错,Windows正是使用这几个字符在标题栏上绘图的。其实,Windows中的最“标准”的画箭头的方法就是使用Marlett字体,无论是工具栏上的箭头还是组合框中的箭头,都是这样画出的。有时,在乱删了字体之后,组合框或工具栏的下拉箭头会变成数字6或者9,为什么?看到状态栏上的“击键值”了吗?——“6”,往右数,那个小一点的下箭头正好是——“9”。

下面是具体的制作过程。

首先,生成一个MFC AppWizard EXE 工程,最好是基于对话框的工程,当然,利用现有的工程也可以。

生成一个以CButton为基类的新类,名为CMenuButton,然后用ClassWizard为其添加两个成员函数:DrawItem()和PreSubclassWidnow();手工为CMenuButton类添加BOOL类型m_bDrawFocusRect成员变量,用于决定是否在按钮上画焦点矩形,添加SetDrawFocusRect()函数用于设置这个标志,默认为画焦点矩形;添加两个枚举类型的变量m_ArrowType和m_PopupPos,用于决定所画的箭头的类型和菜单弹出的位置。箭头可为右箭头、下箭头、小右箭头、小下箭头、上箭头和左箭头(参见本文开始处的图);菜单的弹出位置可以为按钮的左上角、右上角、左下角和右下角。最后手工添加两个函数,SetArrowType()和SetMenuPopupPos(),用于设置以上各种风格,其默值分别为画右箭头和在左下角弹出。

如果只需要菜单而不需要画箭头,只需置空BS_OWNERDRAW标志位即可,添加一个SetStyle()函数,用于设置是画箭头还是显示文本,其默认值是画箭头。

为方便处理按钮的BN_CLICKED通知消息,为CMenuButton类创建一个公有的成员函数OnClick(),以便在BN_CLICKED的消息处理器中调用。它有两个参数,第一个是菜单资源的ID,第二个参数为子菜单的ID,默认为0。如果只有一组子菜单,则可使用其默认值0。OnClick()函数的返回值为所选的菜单项的命令ID,若未作任何有效选择,则返回0。

下面是程序代码。

头文件:

#if !defined(_EWAY_MEMUBUTTON_H__INCLUDED_)

#define _EWAY_MEMUBUTTON_H__INCLUDED_

#if _MSC_VER >= 1000

#pragma once

#endif // _MSC_VER >= 1000

// MenuButton.h : header file

//

class CMenuButton : public CButton

{

public:

CMenuButton();

virtual ~CMenuButton();

DECLARE_DYNAMIC( CMenuButton )

enum ArrowType

{

arrowRight,//向右的箭头;

arrowDown, //向下的箭头;

arrowSmallRight, //向右的小箭头;

arrowSmallDown, //向下的小箭头;

arrowUp, //向上的箭头;

arrowLeft//向左的箭头;

}m_ArrowType;

enum PopupPos

{

//名称为TopLeft等等,遵守英文习惯;

posTopLeft, //左上角;

posBottomLeft, //左下角;

posTopRight, //右上角;

posBottomRight, //右下角;

}m_PopupPos;

virtual UINT OnClick(UINT nIDMenuResource,UINT nSubMenu=0);

void SetArrowType(CMenuButton::ArrowType type=CMenuButton::arrowRight);

void SetDrawFocusRect(BOOL bDrawFocusRect=TRUE);

void SetMenuPopupPos(CMenuButton::PopupPos pos=CMenuButton::posBottomLeft);

void SetStyle(BOOL bDrawArrow=TRUE);

// Overrides

// ClassWizard generated virtual function overrides

//{{AFX_VIRTUAL(CMenuButton)

public:

virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);

protected:

virtual void PreSubclassWindow();

//}}AFX_VIRTUAL

protected:

BOOL m_bDrawFocusRect;

//{{AFX_MSG(CMenuButton)

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

//{{AFX_INSERT_LOCATION}}

// Microsoft Developer Studio will insert additional declarations immediately before the previous line.

#endif // !defined(_EWAY_MEMUBUTTON_H__INCLUDED_)

实现文件:

// MenuButton.cpp : implementation file

//

#include "stdafx.h"

#include "MenuButtonTest.h"

#include "MenuButton.h"

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

/////////////////////////////////////////////////////////////////////////////

// CMenuButton

IMPLEMENT_DYNAMIC( CMenuButton, CButton )

CMenuButton::CMenuButton()

{

SetArrowType();

SetDrawFocusRect();

SetMenuPopupPos();

}

CMenuButton::~CMenuButton()

{

}

 

BEGIN_MESSAGE_MAP(CMenuButton, CButton)

//{{AFX_MSG_MAP(CMenuButton)

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////

// CMenuButton message handlers

void CMenuButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)

{

//使用FromeHandle()创建临时的对象,若使用Attach()则必需在最后使用Detach()

CDC *pDC= CDC::FromHandle(lpDrawItemStruct->hDC);

//得到画笔的颜色;

CPen pen;

if( (lpDrawItemStruct->itemState&ODS_DISABLED) )

{

pen.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_GRAYTEXT) );

}

else

{

pen.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_BTNTEXT) );

}

CPen * pOldPen = pDC->SelectObject(&pen);

CFont font;

font.CreateFont(12, 0, 0, 0, FW_NORMAL, 0, 0, 0,

DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,

CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,

DEFAULT_PITCH|FF_SWISS, "Marlett");

CFont * pOldFont=pDC->SelectObject(&font);

CSize size=pDC->GetTextExtent("4",1);

//决定箭头的样子,具体的值可在“字符映射表”中查得;

CString strArrow;

switch (m_ArrowType)

{

case CMenuButton::arrowRight:

strArrow="4";

break;

case CMenuButton::arrowDown:

strArrow="6";

break;

case CMenuButton::arrowSmallRight:

strArrow="8";

break;

case CMenuButton::arrowSmallDown:

strArrow="9";

break;

case CMenuButton::arrowUp:

strArrow="5";

break;

case CMenuButton::arrowLeft:

strArrow="3";

break;

default:

ASSERT(FALSE);

}

//计算座标值,用于绘制箭头;

int x=(lpDrawItemStruct->rcItem.right-lpDrawItemStruct->rcItem.left-size.cx)/2;

int y=(lpDrawItemStruct->rcItem.bottom-lpDrawItemStruct->rcItem.top-size.cy)/2;

//画按钮与箭头;

if( (lpDrawItemStruct->itemState&ODS_SELECTED) )

{

pDC->DrawFrameControl(&lpDrawItemStruct->rcItem, DFC_BUTTON, DFCS_BUTTONPUSH|DFCS_PUSHED);

//在按钮被按下时,上面的字符要有一个向右和向下的偏移;

pDC->TextOut(++x,++y,strArrow);

}

else

{

pDC->DrawFrameControl(&lpDrawItemStruct->rcItem, DFC_BUTTON, DFCS_BUTTONPUSH);

pDC->TextOut(x,y,strArrow);

}

//如果需要,画焦点矩形;

if( (lpDrawItemStruct->itemState&ODS_FOCUS) && m_bDrawFocusRect)

{

CRect rectFocus(lpDrawItemStruct->rcItem);

rectFocus.DeflateRect(3,3); //看起来比较接近的值;

pDC->DrawFocusRect(rectFocus);

}

//仅将对象选回即可,不必调用DeleteTempMap();

pDC->SelectObject(pOldPen);

pDC->SelectObject(pOldFont);

}

UINT CMenuButton::OnClick(UINT nIDMenuResource, UINT nSubMenu/*=0*/)

{

CMenu menu;

//装载菜单;

VERIFY(menu.LoadMenu(nIDMenuResource) );

//得到子菜单;

CMenu *pPopup = menu.GetSubMenu(nSubMenu);//默认为第一组子菜单;

ASSERT(pPopup != NULL);

CRect rect;

GetWindowRect(rect);

POINT point;

//决定弹出菜单的位置;

switch (m_PopupPos)

{

case CMenuButton::posTopLeft://左上角;

point.x=rect.left;

point.y=rect.top;

break;

case CMenuButton::posBottomLeft://左下角;

point.x=rect.left;

point.y=rect.bottom;

break;

case CMenuButton::posTopRight://右上角;

point.x=rect.right;

point.y=rect.top;

break;

case CMenuButton::posBottomRight://右下角;

point.x=rect.right;

point.y=rect.bottom;

break;

default:

ASSERT(FALSE);

}

//弹出菜单;

UINT nMenuSel = pPopup->TrackPopupMenu((TPM_LEFTALIGN|TPM_LEFTBUTTON |TPM_NONOTIFY |TPM_RETURNCMD),point.x, point.y, this);

pPopup->DestroyMenu();

//返回被选择的菜单的ID,如果无任何有效的选择,将返回0;

return nMenuSel;

}

void CMenuButton::PreSubclassWindow()

{

CButton::PreSubclassWindow();

//默认值:加入BS_OWNERDRAW风格;

ModifyStyle(0,BS_OWNERDRAW);

}

void CMenuButton::SetArrowType(CMenuButton::ArrowType type)

{

m_ArrowType=type;

}

void CMenuButton::SetDrawFocusRect(BOOL bDrawFocusRect)

{

m_bDrawFocusRect=bDrawFocusRect;

}

void CMenuButton::SetMenuPopupPos(CMenuButton::PopupPos pos)

{

m_PopupPos=pos;

}

void CMenuButton::SetStyle(BOOL bDrawArrow)

{

if(bDrawArrow)

{

ModifyStyle(0,BS_OWNERDRAW,SWP_NOMOVE|SWP_NOZORDER| SWP_NOSIZE);

}

else

{

ModifyStyle(BS_OWNERDRAW,0,SWP_NOMOVE|SWP_NOZORDER| SWP_NOSIZE);

}

}

要使用这个类,为对话框添加CMenuButton类型的按钮成员变量,若需改变默认风格,则可在OnInitDialog中调用CMenuButton类的公有成员函数SetArrowType()、SetDrawFocusRect()、SetMenuPopupPos()或SetStyle(),在ClassWizard中为对话框添加按钮的BN_CLICKED消息处理函数,然后在其中调用CMenuButton类的OnClick()成员函数,并指定一个菜单ID给它,最后处理OnClick()函数的返回值即可。下面是一个例子。

void CMenuButtonTestDlg::OnTest()

{

UINT nSel=m_btnTest.OnClick(IDR_POPUP);

switch(nSel)

{

case ID_APP_EXIT:

SendMessage(WM_CLOSE,0,0);

break;

case ID_POPUP_ITEM1:

AfxMessageBox("您选择了第一项!");

break;

case ID_POPUP_ITEM2:

AfxMessageBox("您选择了第二项!");

break;

case ID_POPUP_ITEM3:

AfxMessageBox("您选择了第三项!");

break;

default:

//Do nothing;

;

}

}

所用菜单的资源描述如下,外观可参见文首的图。

IDR_POPUP MENU DISCARDABLE

BEGIN

POPUP "_POPUP_"

BEGIN

MENUITEM "第一项", ID_POPUP_ITEM1

MENUITEM "第二项", ID_POPUP_ITEM2

MENUITEM "第三项", ID_POPUP_ITEM3

MENUITEM SEPARATOR

MENUITEM "退出(&X)", ID_APP_EXIT

END

END

BOOL CMenuButtonTestDlg::OnInitDialog()

{

CDialog::OnInitDialog();

//因为这几个值都是默认值,所以注释掉,仅为了演示用法;

//m_btnTest.SetDrawFocusRect(TRUE);

//m_btnTest.ArrowType (CMenuButton::arrowRight);

//m_btnTest.SetStyle(TRUE);

//m_btnTest.SetMenuPopupPos(CMenuButton::posBottomLeft);

return TRUE;

}

值得补充说明的是,使用CMenuButton类的时候,并不一定需要在对话框模板中为按钮指定BS_OWNERDRAW风格,因为在缺省情况下,CMenuButton类的PreSubclassWindow()函数中已经自动加入了这一风格。

 

http://www./article/buttonctrl/1.htm

阅读(283)| 评论(0)
|      
喜欢 推荐 转载

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多