MFC 绘图

目录

MFC中绘图

CPaintDC,封装了在WM_PAINT消息中绘图的绘图设备

CClientDC类,封装了在客户区绘图的绘图设备

CGdiObject类(绘图对象类),封装了各种绘图对象相关的操作


MFC中绘图

Windows绘图需要绘图设备,Win32:绘图设备句柄(HDC);MFC:绘图类对象,本质上还是类绑定句柄。

绘图相关类:

CDC类(绘图设备类):封装了各种绘图相关的函数,以及两个非常重要的的成员变量m_hDC和m_hAttribDC。有以下两个子类:

  • CPaintDC类,封装了在WM_PAINT消息中绘图的绘图设备
  • CClientDC类,封装了在客户区绘图的绘图设备

CGdiObject类(绘图对象类):封装了各种绘图对象相关的操作,以及一个非常重要的成员变量m_hObject(绘图对象句柄),有以下几个子类:

  • CPen类,封装了画笔的操作
  • CBrush类,封装了画刷的操作
  • CFont类,封装了字体的操作
  • CBitmap类,封装了位图的操作

CPaintDC,封装了在WM_PAINT消息中绘图的绘图设备

创建一个单文档视图架构的项目,视图类管理视图窗口,是现实图像用的,应该在视图类中使用绘图类。处理WM_PAINT消息,类向导如下:

处理WM_PAINT消息

void CMFCDrawView::OnPaint()
{CPaintDC dc(this); //::BeginPaint
//	dc.Rectangle( 100, 100, 300, 300 );//::Rectangle(...)
//	::Rectangle( dc.m_hDC, 100, 100, 300, 300 );
}

绘图类谁也代表不了,无法代表绘图设备,只有和绘图设备句柄绑定才行。

下断点,看看CPaintDC的构造函数,参数是视图类对象地址,函数内部this是CPaintDC对象地址

函数伪代码如下:

CPaintDC dc(pView) === CPaintDC::CPaintDC(...)//函数内部this为&dc
{Attach(::BeginPaint(pView->m_hWnd, &m_ps))//函数内部this为&dc{m_hDC = hDC;//将BeginPaint获取的绘图设备句柄  保存到dc对象的一个成员变量中SetAttribDC(m_hDC)//函数内部this为&dc{m_hAttribDC = m_hDC;//dc对象的另一个成员变量也保存了绘图设备句柄}}
}

所以m_hDC和m_hAttribDC保存的是绘图设备句柄,本质上依然是Windows API

_AFXWIN_INLINE BOOL CDC::Rectangle(int x1, int y1, int x2, int y2){ ASSERT(m_hDC != NULL); return ::Rectangle(m_hDC, x1, y1, x2, y2); }

等价于

::rectangle( dc.m_hdc, 100, 100, 300, 300 );

在Win API 编程,使用绘图设备,需要有拿到绘图设备句柄和释放。在MFC中这个任务就交给了构造函数和析构函数。

CPaintDC::CPaintDC(CWnd* pWnd)
{ASSERT_VALID(pWnd);ASSERT(::IsWindow(pWnd->m_hWnd));if (!Attach(::BeginPaint(m_hWnd = pWnd->m_hWnd, &m_ps)))   // 获取绘图设备句柄AfxThrowResourceException();
}CPaintDC::~CPaintDC()
{ASSERT(m_hDC != NULL);ASSERT(::IsWindow(m_hWnd));::EndPaint(m_hWnd, &m_ps);          // 释放绘图设备句柄Detach();
}

代码如下:

void CMFCDrawView::OnPaint()
{CPaintDC dc(this); // device context for painting// TODO: 在此处添加消息处理程序代码// 不为绘图消息调用 CView::OnPaint()dc.Rectangle(100, 100, 300, 300);//::Rectangle(dc.m_hDC, 100, 100, 300, 300);
}

结果如下:

CClientDC类,封装了在客户区绘图的绘图设备

给菜单新加一项,ID为 ID_Client

使用类向导处理点击后的WM_COMMAND消息,四个框架类都可以处理,因为是在视图窗口绘图,所以在视图窗口处理。

生成函数,函数内部this是视图窗口对象地址,用于在视图窗口的客户区的窗口绘图

结果如下:

但是当窗口放大缩小后,圆形消失不见了,但是矩形还在。

原因:触发WM_PAINT消息后,OnPaint函数就会被触发执行,所以矩形一致都在,而OnClient则不是。

CGdiObject类(绘图对象类),封装了各种绘图对象相关的操作

拿画笔举例子:

  1. 创建一根画笔
  2. 把画笔给绘图设备
  3. 使用画笔画画
  4. 要回画笔
  5. 销毁画笔

创建如下4个菜单项

创建处理WM_COMMAND消息的函数

画笔:

void CMFCDrawView::OnPen()
{CClientDC dc( this );CPen pen(PS_SOLID, 2, RGB(255,0,0));  // 实心 像素为2 颜色为红色CPen* oldpen = dc.SelectObject( &pen );//HGDIOBJ nOldPen = ::SelectObject( dc.m_hDC, pen.m_hObject );dc.Rectangle( 100, 100, 300, 300 );//::Rectangle( dc.m_hDC, 100, 100, 300, 300 );dc.SelectObject( oldpen );//::SelectObject( dc.m_hDC, nOldPen );pen.DeleteObject( );//::DeleteObject( pen.m_hObject );
}

跟下CPen的构造函数,伪代码如下:其它也是同理

CPen pen(PS_SOLID, 2, RGB(255,0,0)) === CPen::CPen(PS_SOLID, 2, RGB(255,0,0))
//函数内部this &pen
{Attach(::CreatePen(PS_SOLID, 2, RGB(255,0,0)))//函数内部this &pen{m_hObject = hObject;//将::CreatePen获取的画笔句柄,保存到pen对象的一个成员变量中}
}

画刷:

void CMFCDrawView::OnBrush()
{CClientDC dc(this);CBrush brush(RGB(0,255,0));CBrush* oldbrush = dc.SelectObject( &brush );dc.Rectangle( 100, 100, 300, 300 );dc.SelectObject( oldbrush );brush.DeleteObject( );
}

字体

void CMFCDrawView::OnFont()
{CClientDC dc( this );CFont font;font.CreatePointFont(300, "黑体");//::CreateFont(..............)CFont* oldfont = dc.SelectObject( &font );dc.TextOut( 100, 100, "hello");dc.SelectObject( oldfont );font.DeleteObject();
}

位图:

  1. 添加位图资源
  2. 创建一个和当前DC相匹配的内存DC
  3. 将位图的数据给内存DC
  4. 成像
  5. 将位图数据要回来
  6. 销毁位图
  7. 销毁内存DC

void CMFCDrawView::OnBmp()
{//添加位图资源(操作资源无需写代码)//创建一个和当前DC,相匹配的内存DCCClientDC dc( this );CDC memdc;memdc.CreateCompatibleDC( &dc ); //::CreateCompatibleDC//将位图的数据送给内存DCCBitmap bmp;bmp.LoadBitmap( IDB_BITMAP1 ); //::LoadBitmapCBitmap* oldbmp = memdc.SelectObject( &bmp );//::SelectObject//成像dc.BitBlt( 100, 100, 48, 48, &memdc, 0, 0, SRCCOPY );//::BitBlt//将位图数据要回来memdc.SelectObject( oldbmp );//::SelectObject//销毁位图bmp.DeleteObject( );//::DeleteObject//销毁内存DCmemdc.DeleteDC( );//::DeleteDC
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/632674.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

react + antd:AutoComplete 实现既可以自由输入又能下拉选择

在工作中遇到一个需求,既能下拉选择,有要求可以自由输入没有的选项。 刚开始考虑使用 Select 组件,发现只有多选(mode"tags")的时候才能随意输入内容,但多选又不符合当前的业务需求。 在犹豫要…

Ubuntu防火墙管理

防火墙管理 防火墙是用于监控和过滤传入和传出网络流量的工具。 它通过定义一组确定是允许还是阻止特定流量的安全规则来工作。 Ubuntu 18.04安装了一个称为UFW的防火墙配置工具。 它是用于管理iptables防火墙规则的用户友好型前端。 它的主要目标是使防火墙的管理变得更容易…

pyqtgraph绘图类

pyqtgraph绘图类 pyqtgraph绘图有四种方法: 方法描述pyqtgraph.plot()创建一个新的QWindow用来绘制数据PlotWidget.plot()在已存在的QWidget上绘制数据PlotItem.plot()在已存在的QWidget上绘制数据GraphicsLayout.addPlot()在网格布局中添加一个绘图 上面四个方法都接收同样…

OpenHarmony应用开发-进程间通讯

版本:v3.2 Beta5 进程模型 OpenHarmony的进程模型如下图所示: 应用中(同一包名)的所有UIAbility、ServiceExtensionAbility、DataShareExtensionAbility运行在同一个独立进程中,即图中绿色部分的“Main Process”。…

Linux设备驱动开发学习笔记(等待队列,锁,字符驱动程序,设备树,i2C...)

1. 内核工具和辅助函数 1.1宏container_of container_of函数可以通过结构体的成员变量检索出整个结构体 函数原型: /* pointer 指向结构体字段的指针 container_type 结构体类型 container_field 结构体字段名称 返回值是一个指针 */ container_of(pointer, con…

HPsocket 在 C# 中的运用:一款优秀的 socket 通信框架

摘要:本文将为您详细介绍 HPsocket,一款适用于 win32 平台的 socket 通信框架。同时,我们还将探讨如何在 C# 项目中使用 HPsocket,实现网络通信功能。通过本文,您将深入了解 HPsocket 的特点、优势以及在 C# 中的实际应…

在线App封装技术:HTML5的新生命

HTML5封装的魅力所在HTML5带来了丰富的多媒体功能、地理位置服务、离线存储等特性,使得Web应用的体验更加接近原生App。封装HTML5到App中,可以大大缩短开发周期,降低开发成本,并且一次编写,多平台运行,极大…

MySQL面试题 | 15.精选MySQL面试题

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云…

.NET Core使用SkiaSharp快速生成二维码( 真正跨平台方案)

前言 在.NET 6之前我们一直是使用QRCoder来生成二维码(QRCoder是一个非常强大的生成二维码的组件,用到了System.Drawing.Common 包),然后从.NET 6开始,当为非 Windows 操作系统编译引用代码时,平台分析器会…

阿里云服务器配置选择之线下IDC直接映射

阿里云服务器配置CPU内存和ECS实例规格如何选择?主要用于线下IDC直接映射,可以选择第七代云服务器ECS计算型c7、通用型g7或内存型r7实例,企业级独享型云服务器,企业级实例采用固定CPU调度模式,每个vCPU绑定到一个物理C…

外汇天眼:Alpha Group International在2023财年实现营收同比增长12%

Alpha Group International plc,一家为企业和机构提供金融解决方案的公司,今天发布了截至2023财年的贸易更新。 营收增长12%,达到1.1亿英镑(2022财年:9830万英镑)。 税前利润增长超过140%,达到…

JVM的演变

Java虚拟机(JVM)是Java语言的核心组成部分,它负责将Java字节码转换为机器码并执行。随着时间的推移,JVM在不同版本的JDK中经历了许多演变和改进。本文将深入浅出地介绍从JDK 7到JDK 21不同主流版本的JVM结构变化及其特性&#xff…

一、RHCE--准备工作

一、RHCE---准备工作 1.修改主机地址(由动态IP地址--> 静态IP地址)第一种:通过命令行的方式第二种:通过vim编辑器修改配置文件的方式第三种:通过图形化的方式: 2.软件安装3.关闭防火墙4.禁用selinux 1.修…

xhr、jQuery、axios、fetch、vue-resource简单了解和对比

1. xhr 不常用(太麻烦),一般进行二次封装,或者使用成型的第三方封装jQuery,axios等。axios和jQuery都是对xhr的封装。 2. jQuery 核心是封装Dom操作,80%的内容都是关于Dom的,Vue和React的使用…

【代码随想录算法训练营-第八天】【字符串】344,541,卡码网:54,151,卡码网:55

344.反转字符串 第一遍 思路 class Solution {public void reverseString(char[] s) {char tmp;for (int i 0, j s.length - 1; i < s.length && j > 0 && i < j; i, j--) {tmp s[i];s[i] s[j];s[j] tmp;}} }541. 反转字符串II 第一遍 思路…

kubernetes 权限控制

RBAC引入了4个顶级资源对象&#xff1a;Role、ClusterRole&#xff1a;角色&#xff0c;用于指定一组权限&#xff1b;RoleBinding、ClusterRoleBinding&#xff1a;角色绑定&#xff0c;用于将角色&#xff08;权限&#xff09;赋予给对象 咱们通过Role可以配置命名空间下资源…

第16章_网络编程拓展练习(TCP编程,UDP编程)

文章目录 第16章_网络编程拓展练习TCP编程1、学生与老师交互2、查询单词3、拓展&#xff1a;查询单词4、图片上传5、拓展&#xff1a;图片上传6、多个客户端上传文件7、群聊 UDP编程8、群发消息 第16章_网络编程拓展练习 TCP编程 1、学生与老师交互 案例&#xff1a;客户端模…

springboot3+springsecurity6集成druid启动报错

环境&#xff1a;springboot3security6druid1.2.20 druid1.2.20这个版本开始支持springboot3自动配置&#xff0c;不再需要手动引入 依赖为 <dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-3-starter</artifactId>…

概率论在激光雷达的目标检测和跟踪中的应用

概率论在激光雷达的目标检测和跟踪中发挥着重要的作用&#xff0c;通过建立概率模型和应用贝叶斯推断&#xff0c;可以处理激光雷达数据的不确定性&#xff0c;并提供准确的目标检测和跟踪结果。概率模型是激光雷达目标检测和跟踪的基础。激光雷达可以提供目标的位置、速度和形…

Qt程序如何在Release模式下进行断点调试

有些时候,因为某些工程pro文件设置了debug和Release版本的原因,导致在编译运行的时候,程序会自动生成带d后缀的一些库文件,进行调试。 debug模式下我们打断点进行调试,大家都知道。但是Release模式下,如果你直接Ctrl + R运行,肯定是无法断点调试的。 那么这个时候,我…