MFC自绘Button按钮分析和实现

转自:https://blog.csdn.net/c_base_jin/article/details/53726209

对于按压式的Button按钮,WM_CTLCOLOR无法完成按钮控件的背景颜色和字体颜色修改,若想要完成外观定制需要添加WM_DRAWITEM消息或者重写CButton类中的DrawItem函数完成按钮外观修改,下面逐一介绍。


自绘制知识基础


自绘制需要的两个基础步骤:

1.控件类型设置为 BS_OWNERDRAW

2.添加WM_DRAWITEM消息响应函数或者重写DrawItem函数。


WM_DRAWITEM消息响应原型如下:

[cpp]  view plain  copy
  1. afx_msg void OnDrawItem( int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct );  
  2.   
  3. 参数:   
  4. nIDCtl   
  5.     包含了发送WM_DRAWITEM消息的控件的标识符。如果菜单发送了此消息,则nIDCtl中包含0。    
  6. lpDrawItemStruct   
  7.     指定了指向DRAWITEMSTRUCT数据结构的长指针,其中包含有关要画出的项和要求的绘图类型的信息。  

说明:
当控件或菜单的可视状态发生变化时,框架为自画按钮控件、组合框控件、列表框控件或者菜单的拥有者调用这个成员函数。

DRAWITEMSTRUCT结构体信息如下:

[cpp]  view plain  copy
  1. typedef struct tagDRAWITEMSTRUCT   
  2. {  
  3.   UINT CtlType;     
  4.   UINT CtlID;     
  5.   UINT itemID;   
  6.   UINT itemAction;     
  7.   UINT itemState;     
  8.   HWND hwndItem;     
  9.   HDC hDC;     
  10.   RECT rcItem;   
  11.   ULONG_PTR itemData;   
  12. } DRAWITEMSTRUCT;   

DrawItem函数原型如下,入参和OnDrawItem一样,不再重复介绍:
[cpp]  view plain  copy
  1. virtual void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/);  

需要说明的是,若某个控件拥有了BS_OWNERDRAW属性,则控件的绘制将由父窗口完成转移给了“程序员”,程序员需要完成所有的绘制工作,也就实现了控件自绘,若没有完成控件绘制功作,我们在界面上将看不到对应的控件,我们在重绘某个控件时,强烈推荐使用子类化方法,比如想自绘Button控件, 首先添加自己的类CMYButton 继承自 CButton,这样的设计符合程序设计思想,避免了父类功能的臃肿,也实现了程序的复用。



自绘制原理分析


自绘基本流程我已经绘制成流程图了,这样也清晰易懂,图中的数字标识也给出了简单介绍,自绘流程如图1所示:

                                                                     图1 自绘制原理


1.子控件将要被绘制时,检测该控件有BS_OWNERDRAW属性,则向父窗口发送WM_DRAWITEM消息
2.父窗口完成收集和准备控件绘制所必要的信息
3.若ReflectLastMsg函数返回TRUE,表示消息反射成功,使用子控件中的绘制代码
4.若ReflectLastMsg函数返回FALSE,表示消息反射失败,使用父窗口中的绘制代码
5.消息反射成功了,我们就可以重写CButton中DrawItem虚函数完成控件自绘制


下面将展示如何完成控件的绘制步骤:

1.基于对话框建立DrawButton工程

2.添三个按压式Button控件,其ID分别四IDC_YES,IDC_NO, IDC_HELP如图2所示:


                                  图2  控件布局


3.分别在父窗口(对话框)和子类化中实现自绘,具体过程如下:


父窗口中实现自绘制


具体过程:类视图->属性->查找WM_WM_DRAWITEM->添加并编辑"OnDrawItem",其代码如下:

[cpp]  view plain  copy
  1. void CDrawButtonDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)  
  2. {  
  3.    // TODO: 在此添加消息处理程序代码和/或调用默认值  
  4.      
  5.    //获得button标题   
  6.    CString btnCaption = _T("Dialog");  
  7.    CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);  
  8.   
  9.    CRect drawRect;  
  10.    //获得绘图DC  
  11.    //得到原Button的矩形大小  
  12.    drawRect.CopyRect(&(lpDrawItemStruct->rcItem));      
  13.    //绘制控件框架   
  14.    pDC->DrawFrameControl(&drawRect,DFC_BUTTON,lpDrawItemStruct->CtlType);  
  15.   
  16.   
  17.    //创建画刷  
  18.    CBrush pBrush;  
  19.    pBrush.CreateSolidBrush(RGB(100,130,10));  
  20.    //画矩形   
  21.    pDC->FillRect(drawRect,&pBrush);  
  22.   
  23.   
  24.    //定义一个CRect用于绘制文本   
  25.    CRect textRect;  
  26.    //拷贝矩形区域   
  27.    textRect.CopyRect(&drawRect);  
  28.    //获得字符串尺寸  
  29.    CSize sz = pDC->GetTextExtent(btnCaption);  
  30.    //调整文本位置 居中   
  31.    textRect.top += (textRect.Height()- sz.cy)/2;  
  32.    //设置文本背景透明   
  33.    pDC->SetBkMode(TRANSPARENT);  
  34.    //设置文本颜色  
  35.    pDC->SetTextColor(RGB(0,0,255));   
  36.    //绘制文本内容  
  37.    pDC->DrawText(btnCaption,&textRect,DT_RIGHT|DT_CENTER|DT_BOTTOM);  
  38.   
  39.    CDialog::OnDrawItem(nIDCtl, lpDrawItemStruct);  
  40. }  


子类化实现自绘制


具体过程:

1.类视图->点击工程名->点击添加->MFC类->基类:CButton,子类命名为CMyButton。

2.资源视图->控件IDC_YES,IDC_HELP添加变量->类型选择为CMyButton。

在自定义的CMyButton中我们添加DrawItem虚函数,其具体代码如下:

[cpp]  view plain  copy
  1. void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)  
  2. {  
  3.     CString btnCaption = "";   
  4.     //设置标题  
  5.     switch (lpDrawItemStruct->CtlID)  
  6.     {  
  7.     case IDC_YES:  
  8.         btnCaption = "Yes";  
  9.         break;  
  10.     case IDC_NO:  
  11.         btnCaption = "No";  
  12.         break;  
  13.     case IDC_HELP:  
  14.         btnCaption = "Help";  
  15.         break;  
  16.     default:  
  17.         ;  
  18.     }   
  19.   
  20.     CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);  
  21.   
  22.     CRect drawRect;  
  23.     //获得绘图DC  
  24.     //得到原Button的矩形大小  
  25.     drawRect.CopyRect(&(lpDrawItemStruct->rcItem));      
  26.     //绘制控件框架   
  27.     pDC->DrawFrameControl(&drawRect,DFC_BUTTON,lpDrawItemStruct->CtlType);  
  28.   
  29.     //使得初始的button颜色不一样  
  30.     static int nStepColor = 0;   
  31.   
  32.     //创建画刷  
  33.     CBrush pBrush;  
  34.     pBrush.CreateSolidBrush(RGB(100+nStepColor,130,nStepColor));  
  35.     //画矩形   
  36.     pDC->FillRect(drawRect,&pBrush);  
  37.   
  38.   
  39.     //定义一个CRect用于绘制文本   
  40.     CRect textRect;  
  41.     //拷贝矩形区域   
  42.     textRect.CopyRect(&drawRect);  
  43.     //获得字符串尺寸  
  44.     CSize sz = pDC->GetTextExtent(btnCaption);  
  45.     //调整文本位置 居中   
  46.     textRect.top += (textRect.Height()- sz.cy)/2;  
  47.     //设置文本背景透明   
  48.     pDC->SetBkMode(TRANSPARENT);  
  49.     //设置文本颜色  
  50.     pDC->SetTextColor(RGB(0,0,255));   
  51.     //绘制文本内容  
  52.     pDC->DrawText(btnCaption,&textRect,DT_RIGHT|DT_CENTER|DT_BOTTOM);  
  53.     nStepColor += 120;  
  54.   
  55. }  
运行效果:


说明中间一个Button按钮的自绘是由父窗口的OnDrawItem实现的。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MFC 中,可以通过 CButton 类的派生类来实现按钮自绘。具体步骤如下: 1. 创建一个自定义的按钮类,继承自 CButton。 2. 在该类中重载 OnDrawItem 函数,在该函数中实现按钮自绘逻辑。 3. 在对话框或窗口类中使用该自定义按钮类。 以下是一个简单的自定义按钮类的示例代码: ```cpp class CMyButton : public CButton { public: CMyButton(); virtual ~CMyButton(); protected: DECLARE_MESSAGE_MAP() afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct); private: COLORREF m_clrBackground; }; CMyButton::CMyButton() { m_clrBackground = RGB(255, 255, 255); } CMyButton::~CMyButton() { } BEGIN_MESSAGE_MAP(CMyButton, CButton) ON_WM_DRAWITEM() END_MESSAGE_MAP() void CMyButton::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) { CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); CRect rect = lpDrawItemStruct->rcItem; // 绘制背景 pDC->FillSolidRect(rect, m_clrBackground); // 绘制文本 CString strText; GetWindowText(strText); pDC->SetTextColor(GetSysColor(COLOR_BTNTEXT)); pDC->SetBkMode(TRANSPARENT); pDC->DrawText(strText, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); } ``` 在对话框或窗口类中,使用该自定义按钮类的示例代码如下: ```cpp CMyButton btn; btn.Create(_T("My Button"), WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, CRect(10, 10, 100, 30), this, IDC_MYBUTTON); ``` 其中,IDC_MYBUTTON 是自定义按钮的 ID。通过调用 Create 函数创建自定义按钮,并指定按钮的样式为 BS_OWNERDRAW,表示按钮使用自绘。然后在 OnDrawItem 函数中,实现自定义按钮的绘制逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值