热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

对于按压式的Button按钮,WM_CTLCOLOR无法完成按钮控件的背景颜色和字体颜色修改,若想要完成外观定制需要添加WM_DRAWITEM消息或者重

对于按压式的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实现的。

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



推荐阅读
  • WPF项目学习.一
    WPF项目搭建版权声明:本文为博主初学经验,未经博主允许不得转载。一、前言记录在学习与制作WPF过程中遇到的解决方案。使用MVVM的优点是数据和视图分离,双向绑定,低耦合,可重用行 ... [详细]
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • 深入解析Java中的空指针异常及其预防策略
    空指针异常(NullPointerException,简称NPE)是Java编程中最常见的异常之一。尽管其成因显而易见,但开发人员往往容易忽视或未能及时采取措施。本文将详细介绍如何有效避免空指针异常,帮助开发者提升代码质量。 ... [详细]
  • vue引入echarts地图的四种方式
    一、vue中引入echart1、安装echarts:npminstallecharts--save2、在main.js文件中引入echarts实例:  Vue.prototype.$echartsecharts3、在需要用到echart图形的vue文件中引入:   importechartsfrom"echarts";4、如果用到map(地图),还 ... [详细]
  • 我有一个从C项目编译的.o文件,该文件引用了名为init_static_pool ... [详细]
  • 更新vuex的数据为什么用mutation?
    更新vuex的数据为什么用mutation?,Go语言社区,Golang程序员人脉社 ... [详细]
  • Hadoop的文件操作位于包org.apache.hadoop.fs里面,能够进行新建、删除、修改等操作。比较重要的几个类:(1)Configurati ... [详细]
  • 如果应用程序经常播放密集、急促而又短暂的音效(如游戏音效)那么使用MediaPlayer显得有些不太适合了。因为MediaPlayer存在如下缺点:1)延时时间较长,且资源占用率高 ... [详细]
  • Spring – Bean Life Cycle
    Spring – Bean Life Cycle ... [详细]
  • DAO(Data Access Object)模式是一种用于抽象和封装所有对数据库或其他持久化机制访问的方法,它通过提供一个统一的接口来隐藏底层数据访问的复杂性。 ... [详细]
  • Java 中的等时日期(int,int)方法,示例 ... [详细]
  • Java设计模式详解:解释器模式的应用与实现
    本文详细介绍了Java设计模式中的解释器模式,包括其定义、应用场景、优缺点以及具体的实现示例。通过音乐解释器的例子,帮助读者更好地理解和应用这一模式。 ... [详细]
  • 普通树(每个节点可以有任意数量的子节点)级序遍历 ... [详细]
  • C#实现文件的压缩与解压
    2019独角兽企业重金招聘Python工程师标准一、准备工作1、下载ICSharpCode.SharpZipLib.dll文件2、项目中引用这个dll二、文件压缩与解压共用类 ... [详细]
  • 在《Cocos2d-x学习笔记:基础概念解析与内存管理机制深入探讨》中,详细介绍了Cocos2d-x的基础概念,并深入分析了其内存管理机制。特别是针对Boost库引入的智能指针管理方法进行了详细的讲解,例如在处理鱼的运动过程中,可以通过编写自定义函数来动态计算角度变化,利用CallFunc回调机制实现高效的游戏逻辑控制。此外,文章还探讨了如何通过智能指针优化资源管理和避免内存泄漏,为开发者提供了实用的编程技巧和最佳实践。 ... [详细]
author-avatar
萌星
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有