c语言自绘按钮例子,MFC自绘Button按钮分析和实现

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

自绘制知识基础

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

1.控件类型设置为 BS_OWNERDRAW

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

WM_DRAWITEM消息响应原型如下:

afx_msg void OnDrawItem( int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct );

参数:

nIDCtl

包含了发送WM_DRAWITEM消息的控件的标识符。如果菜单发送了此消息,则nIDCtl中包含0。

lpDrawItemStruct

指定了指向DRAWITEMSTRUCT数据结构的长指针,其中包含有关要画出的项和要求的绘图类型的信息。

说明:

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

DRAWITEMSTRUCT结构体信息如下:

typedef struct tagDRAWITEMSTRUCT

{

UINT CtlType;

UINT CtlID;

UINT itemID;

UINT itemAction;

UINT itemState;

HWND hwndItem;

HDC hDC;

RECT rcItem;

ULONG_PTR itemData;

} DRAWITEMSTRUCT;

DrawItem函数原型如下,入参和OnDrawItem一样,不再重复介绍:

virtual void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/);

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

自绘制原理分析

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

94f0d293df116bcca2edc88abedba854.png

图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所示:

eb4afc0894239873278efcf6e2847cb6.png

图2  控件布局

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

父窗口中实现自绘制

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

void CDrawButtonDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)

{

// TODO: 在此添加消息处理程序代码和/或调用默认值

//获得button标题

CString btnCaption = _T("Dialog");

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

CRect drawRect;

//获得绘图DC

//得到原Button的矩形大小

drawRect.CopyRect(&(lpDrawItemStruct->rcItem));

//绘制控件框架

pDC->DrawFrameControl(&drawRect,DFC_BUTTON,lpDrawItemStruct->CtlType);

//创建画刷

CBrush pBrush;

pBrush.CreateSolidBrush(RGB(100,130,10));

//画矩形

pDC->FillRect(drawRect,&pBrush);

//定义一个CRect用于绘制文本

CRect textRect;

//拷贝矩形区域

textRect.CopyRect(&drawRect);

//获得字符串尺寸

CSize sz = pDC->GetTextExtent(btnCaption);

//调整文本位置 居中

textRect.top += (textRect.Height()- sz.cy)/2;

//设置文本背景透明

pDC->SetBkMode(TRANSPARENT);

//设置文本颜色

pDC->SetTextColor(RGB(0,0,255));

//绘制文本内容

pDC->DrawText(btnCaption,&textRect,DT_RIGHT|DT_CENTER|DT_BOTTOM);

CDialog::OnDrawItem(nIDCtl, lpDrawItemStruct);

}

子类化实现自绘制

具体过程:

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

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

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

void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)

{

CString btnCaption = "";

//设置标题

switch (lpDrawItemStruct->CtlID)

{

case IDC_YES:

btnCaption = "Yes";

break;

case IDC_NO:

btnCaption = "No";

break;

case IDC_HELP:

btnCaption = "Help";

break;

default:

;

}

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

CRect drawRect;

//获得绘图DC

//得到原Button的矩形大小

drawRect.CopyRect(&(lpDrawItemStruct->rcItem));

//绘制控件框架

pDC->DrawFrameControl(&drawRect,DFC_BUTTON,lpDrawItemStruct->CtlType);

//使得初始的button颜色不一样

static int nStepColor = 0;

//创建画刷

CBrush pBrush;

pBrush.CreateSolidBrush(RGB(100+nStepColor,130,nStepColor));

//画矩形

pDC->FillRect(drawRect,&pBrush);

//定义一个CRect用于绘制文本

CRect textRect;

//拷贝矩形区域

textRect.CopyRect(&drawRect);

//获得字符串尺寸

CSize sz = pDC->GetTextExtent(btnCaption);

//调整文本位置 居中

textRect.top += (textRect.Height()- sz.cy)/2;

//设置文本背景透明

pDC->SetBkMode(TRANSPARENT);

//设置文本颜色

pDC->SetTextColor(RGB(0,0,255));

//绘制文本内容

pDC->DrawText(btnCaption,&textRect,DT_RIGHT|DT_CENTER|DT_BOTTOM);

nStepColor += 120;

}

运行效果:

f33c2afe46ca5697d3e1525dd9c9bd65.png

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值