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消息

cpp 复制代码
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对象地址

函数伪代码如下:

cpp 复制代码
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

cpp 复制代码
_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); }

等价于

cpp 复制代码
::rectangle( dc.m_hdc, 100, 100, 300, 300 );

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

cpp 复制代码
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();
}

代码如下:

cpp 复制代码
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消息的函数

画笔:

cpp 复制代码
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的构造函数,伪代码如下:其它也是同理

cpp 复制代码
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对象的一个成员变量中
  }
}

画刷:

cpp 复制代码
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( );
}

字体

cpp 复制代码
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
cpp 复制代码
void CMFCDrawView::OnBmp()
{
	//添加位图资源(操作资源无需写代码)

	//创建一个和当前DC,相匹配的内存DC
	CClientDC dc( this );
	CDC memdc;
	memdc.CreateCompatibleDC( &dc ); //::CreateCompatibleDC
	//将位图的数据送给内存DC
	CBitmap bmp;
	bmp.LoadBitmap( IDB_BITMAP1 ); //::LoadBitmap


	CBitmap* oldbmp = memdc.SelectObject( &bmp );//::SelectObject
	//成像
	dc.BitBlt( 100, 100, 48, 48, &memdc, 0, 0, SRCCOPY );//::BitBlt
	//将位图数据要回来
	memdc.SelectObject( oldbmp );//::SelectObject
	//销毁位图
	bmp.DeleteObject( );//::DeleteObject
	//销毁内存DC
	memdc.DeleteDC( );//::DeleteDC
}
相关推荐
未来可期LJ36 分钟前
【C++ 设计模式】单例模式的两种懒汉式和饿汉式
c++·单例模式·设计模式
Trouvaille ~1 小时前
【C++篇】C++类与对象深度解析(六):全面剖析拷贝省略、RVO、NRVO优化策略
c++·c++20·编译原理·编译器·类和对象·rvo·nrvo
little redcap2 小时前
第十九次CCF计算机软件能力认证-乔乔和牛牛逛超市
数据结构·c++·算法
机器视觉知识推荐、就业指导2 小时前
Qt/C++事件过滤器与控件响应重写的使用、场景的不同
开发语言·数据库·c++·qt
孤寂大仙v2 小时前
【C++】STL----list常见用法
开发语言·c++·list
咩咩大主教3 小时前
C++基于select和epoll的TCP服务器
linux·服务器·c语言·开发语言·c++·tcp/ip·io多路复用
Ylucius5 小时前
动态语言? 静态语言? ------区别何在?java,js,c,c++,python分给是静态or动态语言?
java·c语言·javascript·c++·python·学习
是店小二呀5 小时前
【C++】C++ STL探索:Priority Queue与仿函数的深入解析
开发语言·c++·后端
ephemerals__5 小时前
【c++】动态内存管理
开发语言·c++
CVer儿5 小时前
条件编译代码记录
开发语言·c++