用VC制作带弹出式菜单的按钮(整理以后的扩展类)

这个博客介绍如何使用VC++创建一个带有弹出式菜单的自定义按钮类CMenuButton。类包含了构造、属性设置、绘制方法以及响应鼠标事件的处理,实现了按钮的不同状态效果,并能在点击按钮时显示指定的菜单。

//头文件

#if !defined(AFX_MENUBUTTON_H__B0745FB2_A382_4B46_8C67_B5369E51CB91__INCLUDED_)
#define AFX_MENUBUTTON_H__B0745FB2_A382_4B46_8C67_B5369E51CB91__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// MenuButton.h : header file
//

/////////////////////////////////////////////////////////////////////////////
// CMenuButton window

class CMenuButton : public CButton
{
// Construction
public:
 CMenuButton();

// Attributes
public:
     CRect  m_ButRect;
  CRect  m_LRect;
  CRect  m_RRect;
  int    m_State;
  BOOL   b_InFlag;
  BOOL   b_ClickFlag;
  BOOL   b_ClickBut;
  CMenu  m_Menu;
     COLORREF m_BackColor;
  COLORREF m_ForeColor;
  CString  m_strText;
  int      m_MenuID;
// Operations
public:

// Overrides
 // ClassWizard generated virtual function overrides
 //{{AFX_VIRTUAL(CMenuButton)
 public:
 virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
 protected:
 virtual void PreSubclassWindow();
 //}}AFX_VIRTUAL

// Implementation
public:
 BOOL isClick();
 void SetBkColor(COLORREF color);
 void SetForeColor(COLORREF color);
 void SetText(CString str);
 void SetMenuID(int nID);
 void DrawButton(CDC *pDC);
 virtual ~CMenuButton();

 // Generated message map functions
protected:
 //{{AFX_MSG(CMenuButton)
 afx_msg void OnMouseMove(UINT nFlags, CPoint point);
 afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
 afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
 //}}AFX_MSG

 DECLARE_MESSAGE_MAP()
};

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

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_MENUBUTTON_H__B0745FB2_A382_4B46_8C67_B5369E51CB91__INCLUDED_)
 

 

//CPP文件

 

// MenuButton.cpp : implementation file
//

#include "stdafx.h"
#include "对话框菜单禁用.h"
#include "MenuButton.h"

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

/////////////////////////////////////////////////////////////////////////////
// CMenuButton

CMenuButton::CMenuButton()
{

 m_MenuID = 0; //菜单ID
 b_InFlag = false; //进入标志
 m_State = 0; //初始状态
 b_ClickFlag = false; //单击选择区标志
 b_ClickBut = false; //单击主体区标志
 m_strText = _T(""); //按钮文本
 m_ForeColor = RGB(0,0,0); //文字颜色
 m_BackColor = GetSysColor( COLOR_3DFACE ); //背景色


}

CMenuButton::~CMenuButton()
{
}


BEGIN_MESSAGE_MAP(CMenuButton, CButton)
 //{{AFX_MSG_MAP(CMenuButton)
 ON_WM_MOUSEMOVE()
 ON_WM_LBUTTONDOWN()
 ON_WM_LBUTTONUP()
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMenuButton message handlers

void CMenuButton::PreSubclassWindow()
{
 // TODO: Add your specialized code here and/or call the base class
 ModifyStyle( 0, BS_OWNERDRAW ); //设置按钮属性为自绘式

 CButton::PreSubclassWindow();
}

 

void CMenuButton::DrawButton(CDC *pDC)
{
 m_LRect.SetRect( m_ButRect.left, m_ButRect.top,
  m_ButRect.right-21, m_ButRect.bottom ); //按钮主体区尺寸
 
 
 
 m_RRect.SetRect( m_ButRect.right-20, m_ButRect.top,
  m_ButRect.right, m_ButRect.bottom ); //按钮选择区尺寸
 
 
 CPen Pen;
 
 Pen.CreatePen(PS_SOLID, 1, RGB(192,192,192) );
 pDC->SelectObject( &Pen );
 
 pDC->FillSolidRect( m_ButRect, m_BackColor ); //画背景
 switch( m_State ) //不同状态画不同边框
 {
 case 0: //正常按钮
  pDC->DrawEdge( &m_LRect, BDR_RAISEDINNER, BF_RECT );
  pDC->DrawEdge( &m_RRect, BDR_RAISEDINNER, BF_RECT );
  break;
 case 1: //鼠标进入时的按钮
  pDC->DrawEdge( &m_LRect, BDR_RAISEDINNER, BF_RECT );
  pDC->DrawEdge( &m_RRect, BDR_RAISEDINNER, BF_RECT );
  pDC->MoveTo( m_ButRect.TopLeft() );
  pDC->LineTo( m_ButRect.right, m_ButRect.top );
  break;
 case 2: //单击按钮主体区时的按钮
  pDC->DrawEdge( &m_RRect, BDR_RAISEDINNER, BF_RECT );
  break;
 case 3: //单击按钮选择区时的按钮
  pDC->DrawEdge( &m_LRect, BDR_RAISEDINNER, BF_RECT );
  break;
 }
 
 POINT m_pt[3], m_ptCentre; //箭头坐标(三个顶点)
 m_ptCentre = m_RRect.CenterPoint(); //选择区中点位置
 m_pt[0].x = m_ptCentre.x-3; //计算箭头坐标
 m_pt[0].y = m_ptCentre.y-2;
 m_pt[1].x = m_ptCentre.x+4;
 m_pt[1].y = m_ptCentre.y-2;
 m_pt[2].x = m_ptCentre.x;
 m_pt[2].y = m_ptCentre.y+2;
 
 pDC->SelectStockObject( BLACK_BRUSH ); //定义画刷(黑色)
 CRgn rgn;
 rgn.CreatePolygonRgn( m_pt, 3, ALTERNATE );
 pDC->PaintRgn( &rgn ); //画选择区箭头
 
 pDC->SetTextColor( m_ForeColor ); //画主体区文字
 pDC->SetBkMode( TRANSPARENT );
 pDC->DrawText( m_strText, &m_LRect, DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_END_ELLIPSIS);
 
}

void CMenuButton::OnMouseMove(UINT nFlags, CPoint point)
{
 // TODO: Add your message handler code here and/or call default
 if( !b_InFlag || GetCapture()!=this ) //鼠标进入按钮
 {
  b_InFlag = true; //设置进入标志
  SetCapture(); //捕获鼠标
  m_State = 1; //置按钮状态(1-当前按钮)
  if( b_ClickFlag ) //检测单击选择区标志
  {
   m_Menu.Detach(); //清除打开的菜单
   m_Menu.DestroyMenu();
   b_ClickFlag = false;
  }
  Invalidate(); //重绘按钮
 }
 else
 {
  if ( !m_ButRect.PtInRect(point) ) //鼠标离开按钮
  {
   b_InFlag = false; //清除进入标志
   ReleaseCapture(); //释放鼠标捕获
   b_ClickBut = false; //清除单击标志
   m_State = 0; //置按钮状态(0-正常按钮)
   if( b_ClickFlag ) //检测单击选择区标志
   {
    m_Menu.Detach(); //清除打开的菜单
    m_Menu.DestroyMenu();
    b_ClickFlag = false;
   }
   Invalidate(); //重绘按钮
  }
 }
 CButton::OnMouseMove(nFlags, point);
}

void CMenuButton::OnLButtonDown(UINT nFlags, CPoint point)
{
 // TODO: Add your message handler code here and/or call default
 if( m_LRect.PtInRect(point) ) //单击按钮主体区
 {
  m_State = 2; //置按钮状态(2-正常按钮)
  b_ClickBut = true; //设置单击按钮标志
  Invalidate(); //重绘按钮
 }
 else if( m_RRect.PtInRect(point) && m_MenuID ) //单击选择区
 {
  m_State = 3;
  b_ClickBut = false; //清除单击按钮标志
  Invalidate(); //重绘按钮
  b_ClickFlag = !b_ClickFlag; //单击选择区标志
  if( b_ClickFlag ) //一次单击,弹出菜单
  {
   CRect rect = m_RRect;
   ClientToScreen(rect); //转换为屏幕坐标
   point = rect.BottomRight();
   point.x -= rect.Width(); //设置弹出菜单的位置
   
   VERIFY(m_Menu.LoadMenu(m_MenuID)); //装入菜单资源
   
   CMenu* pPopup = m_Menu.GetSubMenu(0);
   ASSERT(pPopup != NULL);
   CWnd* pWndPopupOwner = this;
   
   while (pWndPopupOwner->GetStyle() & WS_CHILD)
    pWndPopupOwner = pWndPopupOwner->GetParent();
   
   pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON, point.x, point.y, pWndPopupOwner); //弹出菜单
  }
  else //再次单击,清除菜单
  {
   m_Menu.Detach();
   m_Menu.DestroyMenu();
  }
 }

 CButton::OnLButtonDown(nFlags, point);
}

void CMenuButton::OnLButtonUp(UINT nFlags, CPoint point)
{
 // TODO: Add your message handler code here and/or call default
    m_State = 0; //恢复为正常按钮
    Invalidate(); //重绘按钮

 CButton::OnLButtonUp(nFlags, point);
}

void CMenuButton::SetMenuID(int nID)
{
 m_MenuID = nID;

}

void CMenuButton::SetText(CString str)
{
 m_strText = str;
}

void CMenuButton::SetForeColor(COLORREF color)
{
 m_ForeColor = color;
 Invalidate();
}

void CMenuButton::SetBkColor(COLORREF color)
{
 m_BackColor = color;
   this->Invalidate();
}

BOOL CMenuButton::isClick()
{
 return b_ClickBut;
}

 

void CMenuButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
 // TODO: Add your code to draw the specified item
  CDC *pDC = CDC::FromHandle( lpDrawItemStruct->hDC );

 m_ButRect = lpDrawItemStruct->rcItem; //获取按钮尺寸
 int nSavedDC = pDC->SaveDC();
 VERIFY( pDC );
 
 DrawButton(pDC); //绘制按钮
 
 pDC->RestoreDC( nSavedDC );
}

//调用

 m_1.SetMenuID(IDR_MENU1);
 m_1.SetText("弹出菜单按钮");
 m_1.SetBkColor(RGB(125,236,123));
 m_1.SetForeColor(RGB(0,0,255));

 

//执行效果图

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值