MFC第二十二天 三种绘图句柄与三大坐标系(三大CDC派生类)简介以及应用、Invalidate刷新函数的功能和用法简介

news2025/2/26 2:53:13

文章目录

  • 三种绘图句柄与三大坐标系(三大CDC派生类)简介以及应用
    • 三种HDC句柄
    • 三大CDC派生类
    • 什么是放泄露架构
    • 使用HDC句柄进行常见图形绘制演示
  • HPEN和HBRUSH句柄
    • HPEN的创建
  • Invalidate刷新函数的功能和用法简介
  • 应用
    • Win32下
    • MFC下
  • 附录

三种绘图句柄与三大坐标系(三大CDC派生类)简介以及应用

三种HDC句柄

a)标准绘图消息WM_PAINT:,必须使用BeginPaint和EndPaint来绘图。
BeginPaint和EndPaint只能在WM_PAINT中使用。
b)在其他任何消息中使用的绘图句柄叫做临时绘图句柄。
(GetDC和ReleaseDC)
c)标准非客户户区绘图:(不推荐使用)
GetWindowDC和ReleaseDC

非客户区如同一个桌子的桌面,桌面上有桌布,露出了四角就是。
这里要说明的问题是:非客户区不是只有四角。

三大CDC派生类

a)客户区标准绘图:必须由CPaintDC派生类来调用,不能直接调用由CDC基类;
因为CPaintDC类构造函数是调用::BeginPaint,析构函数调用::EndPaint;
CPaintDC类必须在WM_PAINT消息中使用

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();
}

b)非客户区标准绘图,必须由CWindowDC来调用,必须在WM_NCPAINT下执行;
(不推荐使用)内部是构造函数调用GetWindowDC,析构函数调用ReleaseDC

CWindowDC::CWindowDC(CWnd* pWnd)
{
	ASSERT(pWnd == NULL || ::IsWindow(pWnd->m_hWnd));

	if (!Attach(::GetWindowDC(m_hWnd = pWnd->GetSafeHwnd())))
		AfxThrowResourceException();
}
CWindowDC::~CWindowDC()
{
	ASSERT(m_hDC != NULL);
	::ReleaseDC(m_hWnd, Detach());
}

c)客户区临时绘图除了以上两个消息之外,客户区的其他消息都调用CClientDC来执行绘图;
内部是构造函数调用GetDC,析构函数调用RleaseDC。

CClientDC::CClientDC(CWnd* pWnd)
{
	ASSERT(pWnd == NULL || ::IsWindow(pWnd->m_hWnd));

	if (!Attach(::GetDC(m_hWnd = pWnd->GetSafeHwnd())))
		AfxThrowResourceException();
}
CClientDC::~CClientDC()
{
	ASSERT(m_hDC != NULL);
	::ReleaseDC(m_hWnd, Detach());
}

什么是放泄露架构

利用析构函数,无论任何条件返回,析构函数都系统帮你防止泄露

class CPaintDC : public CDC
{// Attributes
protected:
	HWND m_hWnd;
public:
	explicit CPaintDC(CWnd* pWnd);   // BeginPaint

public:
	PAINTSTRUCT m_ps;       // actual paint struct!
// Implementation
public:
	virtual ~CPaintDC();

};

使用HDC句柄进行常见图形绘制演示

HPEN和HBRUSH句柄

a)HPEN是修饰边框,HBRUSH是修饰填充;
b)HPEN可修饰闭合和非闭合图形,HBRUSH只能修饰闭合图形;
c)所有GDI对象的摧毁用DeleteObject,所有GDI对象句柄的信息获取都用GetObject。
d)GetObject反函数是,由详细信息创建句柄,CreateXXXIndirect
!!关注:SelectObject的返回值,是旧对象(OldPen,OldBrush,OldFont等等)

GetObject支持哪些句柄(对应的结构体)
LOGPEN,LOGBRUSH,LOGFONT,BITMAP,

LOGBRUSH logBrush;
GetObject(hBrush, sizeof(LOGBRUSH), &logBrush);

HPEN的创建

HPEN CreatePen(   int fnPenStyle,   int nWidth,   COLORREF crColor);
HPEN CreatePenIndirect(  const LOGPEN* lplgpn);
typedef struct tagLOGPEN
 { 
  UINT lopnStyle; 
  POINT lopnWidth; 
  COLORREF lopnColor; 
} LOGPEN;
PS_SOLID   Creates a solid pen.
PS_DASH  Creates a dashed pen. Valid only when the pen width is 1 or less, in device units.
PS_DOT  Creates a dotted pen. Valid only when the pen width is 1 or less, in device units.
PS_DASHDOT   
Creates a pen with alternating dashes and dots. Valid only when the pen width is 1 or less, in device units.
PS_DASHDOTDOT   
Creates a pen with alternating dashes and double dots. Valid only when the pen width is 1 or less, in device units.
PS_NULL   Creates a null pen.

PS_INSIDEFRAME   Creates a pen that draws a line inside the frame of closed shapes produced by the Windows GDI output functions that specify a bounding rectangle (for example, the Ellipse, Rectangle, RoundRect, Pie, and Chord member functions). When this style is used with Windows GDI output functions that do not specify a bounding rectangle (for example, the LineTo member function), the drawing area of the pen is not limited by a frame.

Invalidate刷新函数的功能和用法简介

InvalidateRect函数用于使指定的矩形区域失效,从而触发重绘操作。其刷新原理如下:

a) InvalidateRect函数会发送WM_PAINT消息给窗口,告诉窗口需要进行绘图操作。窗口收到WM_PAINT消息后,会调用窗口过程中的处理函数,进行标准的绘图操作。

b) 在进行绘图之前,窗口会接收到WM_ERASEBKGND消息,用于擦除当前窗口的背景。这个消息会导致窗口的背景被擦除,以准备进行绘图操作。

c) InvalidateRect函数的第三个参数可以是TRUE或FALSE。当为TRUE时,表示需要同时刷新前景和背景;当为FALSE时,表示只刷新前景。默认情况下,第三个参数为TRUE。

d) UpdateWindow函数用于立即执行窗口的重绘操作,类似于SendMessage函数。它会强制窗口立即进行绘图操作,而不需要等待下一次消息循环。这样可以立即刷新窗口的内容。与之相对,InvalidateRect函数只是标记了指定区域为失效,需要等待下一次绘图消息的到来才会进行绘图操作。

	case WM_SIZE:
	{
		//FALSE  前景覆盖 (WM_PAINT)单层覆盖 TRUE 前景和背景(WM_EARSEBGGND)同时刷新 双层覆盖
		RECT rect{ 300,200,100,200 };
		InvalidateRect(hDlg, NULL, FALSE);
		 //当窗口大小发生变化时 对其刷新 第二个参数为NULL 代表全区域刷新  CRect 可指定
	}
	break;

应用

Win32下

#include<Windows.h>
#include<windowsx.h>
#include<tchar.h>
#include "resource.h"
void OnPaint(HWND hDlg, HDC hdc)
{
	RECT rect;
	GetClientRect(hDlg, &rect);

	HBRUSH hbr = CreateSolidBrush(RGB(102, 250, 230));
	SelectObject(hdc, hbr);
 
	Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom);

	DeleteObject(hbr);

	hbr = CreateSolidBrush(RGB(0, 0, 230));
	SelectObject(hdc, hbr);
	Ellipse(hdc, 10, 10, 300, 200);
	DeleteObject(hbr);

	hbr = CreateSolidBrush(RGB(0, 250, 0));
	SelectObject(hdc, hbr);
	RoundRect(hdc, 300, 300, 500, 400, 50, 50);

	DeleteObject(hbr);

	hbr = CreateSolidBrush(RGB(255, 250, 0));
	SelectObject(hdc, hbr);
	POINT pts[] = { {433,221},{444,555},{777,544} ,{877,444} };
	Polygon(hdc, pts, _countof(pts)); //闭合图形
	DeleteObject(hbr);

	hbr = CreateSolidBrush(RGB(255, 250, 0));
	SelectObject(hdc, hbr);
	POINT pts2[] = { {733,521},{244,155},{377,744} ,{277,244}, {733,521}};
	Polyline(hdc, pts2, _countof(pts2));//非闭合图形 填充颜色也无效

	DeleteObject(hbr);
	SetBkMode(hdc, TRANSPARENT);
	DrawText(hdc, _T("这世间本没有控件"), 8, &rect, DT_CENTER | DT_SINGLELINE | DT_VCENTER);
}

INT_PTR CALLBACK theProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_LBUTTONDOWN:
	{
		int x = LOWORD(lParam);
		int y = HIWORD(lParam);
		HDC hdc = GetDC(hDlg); //临时绘图DC 会被冲毁
		Rectangle(hdc, x - 5, y - 5, x + 5, y + 5);
		ReleaseDC(hDlg, hdc);
		return TRUE;
	}
	case WM_PAINT:
	{
		PAINTSTRUCT ps;
		HDC hdc = BeginPaint(hDlg, &ps);  //hdc 理解为绘图句柄  绑定什么 就绘图什么

		OnPaint(hDlg,hdc);
		//TextOut(hdc,_T("这世间本没有控件"),8);
		EndPaint(hDlg, &ps);  //成对使用
	}
	return TRUE;
	case WM_SIZE:
	{
		//FALSE  前景覆盖 (WM_PAINT)单层覆盖 TRUE 前景和背景(WM_EARSEBGGND)同时刷新 双层覆盖
		RECT rect{ 300,200,100,200 };
		InvalidateRect(hDlg, NULL, FALSE);  
		//当窗口大小发生变化时 对其刷新 第二个参数为NULL 代表全区域刷新  CRect 可指定
	}
	break;
	case WM_COMMAND:
	{
		if (LOWORD(wParam) == IDCANCEL)
			EndDialog(hDlg, IDCANCEL);
	}
	break;
	}
	return FALSE;//return 0代表系统默认要执行的 return 1代表执行系统以外的
}
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	DialogBox(hInstance, MAKEINTRESOURCE(IDD_GDI_DLG), NULL, theProc);
	return 0;
}

MFC下

#include "pch.h"
#include "framework.h"
#include "MFC_GDI.h"
#include "CMainDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif
CMainDlg::CMainDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_MFC_GDI_DIALOG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CMainDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CMainDlg, CDialogEx)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_WM_SIZE()
	ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()

BOOL CMainDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标
	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CMainDlg::OnPaint()
{
	CPaintDC dc(this); // 用于绘制的设备上下文 不用请不要删掉
	RECT rect;
	GetClientRect(&rect);
	CPen p1,p2,p3;
	p1.CreatePen(PS_SOLID, 5, RGB(255, 0, 255));
	auto hOldPen = dc.SelectObject(p1);

	LOGPEN logPen;
	p1.GetObject(sizeof(logPen), &logPen);

	HBRUSH hbr = CreateSolidBrush(RGB(102, 250, 230));
	dc.SelectObject( hbr);
 
	dc.Rectangle(rect.left, rect.top, rect.right, rect.bottom);
	dc.SelectObject(hOldPen);//恢复

	DeleteObject(hbr);

	hbr = CreateSolidBrush(RGB(0, 0, 230));
	dc.SelectObject(hbr);
	dc.Ellipse( 10, 10, 300, 200);
	DeleteObject(hbr);

 
	LOGPEN lp{ PS_NULL };
	p3.CreatePenIndirect(&lp);
	dc.SelectObject(p3);
	dc.RoundRect( 300, 300, 500, 400, 50, 50);


	p2.CreatePen(PS_DASHDOTDOT, 1, RGB(255, 0, 255));
	dc.SelectObject(p2);
	GetObject(p2, sizeof(logPen), &logPen);
	dc.SelectObject(hOldPen);//恢复

	hbr = CreateSolidBrush(RGB(255, 250, 0));
	dc.SelectObject( hbr);
	POINT pts[] = { {433,221},{444,555},{777,544} ,{877,444} };
	dc.Polygon(  pts, _countof(pts)); //闭合图形
	DeleteObject(hbr);

	hbr = CreateSolidBrush(RGB(255, 250, 0));
	dc.SelectObject(  hbr);
	POINT pts2[] = { {733,521},{244,155},{377,744} ,{277,244}, {733,521} };
	dc.Polyline( pts2, _countof(pts2));//非闭合图形 填充颜色也无效

	DeleteObject(hbr);
	dc.SetBkMode(TRANSPARENT);
	dc.DrawText( _T("这世间本没有控件"), 8, &rect, DT_CENTER | DT_SINGLELINE | DT_VCENTER);
}
HCURSOR CMainDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}
void CMainDlg::OnSize(UINT nType, int cx, int cy)
{
	CDialogEx::OnSize(nType, cx, cy);
	this->Invalidate(FALSE);
}

void CMainDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
	CDialogEx::OnLButtonDown(nFlags, point);
	CClientDC dc(this);
	dc.Rectangle(point.x - 10, point.y - 10, point.x + 10, point.y + 10);
}

在这里插入图片描述

附录

DrawText() Format Flags
 
#define DT_TOP                      0x00000000
#define DT_LEFT                     0x00000000
#define DT_CENTER                   0x00000001
#define DT_RIGHT                    0x00000002
#define DT_VCENTER                  0x00000004
#define DT_BOTTOM                   0x00000008
#define DT_WORDBREAK                0x00000010  过长折回
#define DT_SINGLELINE               0x00000020 单行

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

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

相关文章

【算法题解】51. 二叉树的最近公共祖先

这是一道 中等难度 的题 https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/ 题目 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点 p、q&#xff0c;最近公共祖先表示为…

Transformer+医学图像最新进展【2023】

Transformer主要用于自然语言处理领域。近年来,它在计算机视觉(CV)领域得到了广泛的应用。医学图像分析(MIA,Medical image analysis)作为机器视觉(CV,Computer Vision)的一个重要分支,也极大地受益于这一最先进的技术。 机构:新加坡国立大学机械工程系、中山大学智能系…

MySQL创建全文索引时,遇到“Temporary file write failure”的错误

MySQL创建全文索引时&#xff0c;遇到“Temporary file write failure”的错误 环境信息 MySQL Version: 8.0.28 engine: InnoDB rows: 100 index length: 10MB data length: 30MB 笔者在MYSQL上执行创建添加全文索引的语句&#xff1a;alter table users add fulltext index …

机器学习原理(1)集成学习基本方法

一.什么是集成学习 集成学习&#xff08;ensemble learning&#xff09;通过将多个学习器进行组合来完成学习任务。下图显示集成学习的一般结构&#xff08;取自周志华老师的西瓜书&#xff09;&#xff0c;个体学习器通常由一种现有的学习算法从训练数据产生&#xff0c;例如…

Vue项目实战失物招领

经过两天的时间&#xff0c;搞定了一个Vue版本的项目&#xff0c;在这里留下这两天的点点滴滴&#xff0c;这个项目主要实现了失物招领的相关功能&#xff0c;比如发布丢失信息&#xff0c;发布拾到信息&#xff0c;跑腿信息&#xff0c;用户注册&#xff0c;用户登录等相关功能…

故障分析 | Kubernetes 故障诊断流程

一、本文概述及主要术语 1.1 概述 本文基于 Pod 、Service 和 Ingress 三大模块进行划分&#xff0c;对于 Kubernetes 日常可能出现的故障问题&#xff0c;提供了较为具体的排查步骤&#xff0c;并附上相关解决方法或参考文献。 1.2 主要术语 Pod: Kubernetes 中创建和管理的…

Spring Boot日志:SLF4J和Logback

日志的分类 SpringBoot中的日志库分为两种&#xff1a; 实现库&#xff1a;提供具体的日志实现&#xff0c;例如日志级别的控制、打印格式、输出目标等。外观库&#xff1a;自身不提供日志实现&#xff0c;而是对其他日志库进行封装&#xff0c;从而方便使用。基于外观模式实…

接口自动化测试-Python+Requests+Pytest+YAML+Allure配套撸码(详细)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 接口自动化框架&a…

软件测试/测试开发丨Pytest测试框架学习笔记

Pytest 参数化用例 测试登录场景 测试登录成功&#xff0c;登录失败(账号错误&#xff0c;密码错误)*创建多种账号: 中⽂文账号&#xff0c;英⽂文账号*普通测试用例方法Copy 多份代码 or 读⼊入参数?*一次性执⾏多个输⼊入参数* def test_param_login_ok():# 登录成功user…

解决分类任务中数据倾斜问题

大家好&#xff0c;在处理文本分类任务时&#xff0c;基准测试流行的自然语言处理架构的性能是建立对可用选项的理解的重要步骤。在这里&#xff0c;本文将深入探讨与分类相关的最常见的挑战之一——数据倾斜。如果你曾经将机器学习&#xff08;ML&#xff09;应用于真实世界的…

selenium---滑动框验证码破解

前言 目前常见的验证码有很多种&#xff0c;比如数字验证码&#xff0c;滑动验证码&#xff0c;以及滑动补全图像验证码等&#xff0c;关于验证码的操作属于我们在UI自动化很大的一个障碍&#xff0c;今天安静来介绍下如何通过python来实现我们滑动验证码 滑动验证码 先来一…

MySQL之全文索引二三事

全文索引 MySQL全文索引是一种用于快速搜索文本字符串的索引&#xff0c;在MySQL数据库中&#xff0c;它可以用来提高文本搜索的效率。全文索引不同于普通索引&#xff0c;普通索引只是对列值进行排序&#xff0c;而全文索引则会对列的内容进行分词&#xff0c;并且对每个分词…

RocketMQ重复消费的解决方案::分布式锁直击面试!

文章目录 场景分析方法的幂等分布式锁Redis实现分布式锁抢锁的设计思路 分布式锁案例 直击面试rocketmq什么时候重复消费消息丢失的问题消息在哪里丢失发送端确保发送成功并且配合失败的业务处理消费端确保消息不丢失rocketmq 主从同步刷盘 场景分析 分布式系统架构中,队列是分…

go-zero学习 第六章 分布式事务dtm

go-zero学习 第六章 分布式事务dtm 1 参考文档2 官方示例3 go-zero使用dtm参考代码3.1 go-zero支持dtm 代码操作步骤※3.2 gozerodtm 代码操作步骤 4 注意事项4.1 grpc接口地址※4.2 动态调用过程4.3 dtm的回滚补偿4.4 barrier的空补偿、悬挂等4.5 barrier在rpc中本地事务 1 参…

多媒体工作中用到的小工具

安利下嵌入式多媒体用到的各种小工具 下面是同事们推荐的 以下是对这些软件的简要介绍: ocenaudio:ocenaudio是一款跨平台的音频编辑软件,它提供了直观的界面和丰富的功能,可以帮助用户进行音频剪辑、修复、转码等操作。 MKVToolNix:MKVToolNix是一款开源的多媒体容器格…

web-vim信息泄露

&#xff08;1&#xff09;知识补充 vim 交换文件名 在使用vim时会创建临时缓存文件&#xff0c;关闭vim时缓存文件则会被删除&#xff0c;当vim异常退出后&#xff0c;因为未处理缓存文件&#xff0c;导致可以通过缓存文件恢复原始文件内容   以 index.php 为例&#xff1…

Redis一主二从三哨兵模式

文章目录 Redis一主二从三哨兵模式环境配置实践配置主从配置哨兵模式 测试主从复制测试模拟master宕机恢复master Redis一主二从三哨兵模式 当你使用Redis作为主从复制的架构&#xff0c;并且希望在出现主节点故障时自动进行故障转移时&#xff0c;适用于一主而从三哨兵模式。…

android 面试题目之handler消息机制

Handler消息机制是Android里面很基础的东西&#xff0c;基本上属于必考题 一般会从如下几个方面来考查 实现原理&#xff0c;Handler/Message/MessageQueue/Looper 几个类的实现流程&#xff0c;Handler导致的内存泄露怎么处理主线程的Looper是什么时候创建的&#xff1b;如果…

3. Spring 更简单的读取和存储对象(五大类注解 方法注解)

目录 1. 存储 Bean 对象 1.1 配置扫描路径 1.2 添加注解存储 Bean 对象 1.2.1 Controller&#xff08;控制器存储&#xff09; 1.2.2 Service&#xff08;服务存储&#xff09; 1.2.3 Repository&#xff08;仓库存储&#xff09; 1.2.4 Component&#xff08;组件存储&…

C语言学习笔记 Ubuntu系统下部署gcc编译工具-01

在22.04版本 ubuntu系统下&#xff1a; 1.进行apt工具包更新 sudo apt-get update 2.安装gcc工具 sudo apt-get install -y gcc 3.创建一下文件&#xff0c;并编译它输出相应的内容 touch hello.c 4.使用gcc编译c源程序并运行 格式&#xff1a;gcc 源文件名 -o 生成的执行文…