0.题记:

作为QT开发的支持者和践行者,明知道MFC已经过时,但是还不得不用;老板要求,项目组师兄弟代码兼容Balabala~也许这就是中国式项目研发。

好啦,聊点正经事......

1.设备描述表(Device Context,DC):通往各种输出设备的桥梁

在单任务环境如MS-DOS中,运行中的应用程序随时可自由的想做他想做的事,无论是在屏幕上画一条线,重新编写适配器的调色板,还是转换到另一种图像模式。而在窗口化多任务环境如Windows中,程序则无此自由。因为程序A的输出必须与程序B的输出相隔离。首先,这意味着各程序的输出必须限制在自己的窗口中。GDI(Graphic Device Inteface,GDI)使用一简单的机制保证在窗口中画图的各程序遵循这些规则。这种机制即为“设备描述表”,也就是我们常说的DC。

当Windows程序在屏幕、打印机或其他输出设备上画图时,他并不是将像素直接输出到设备上,而是将图绘制到由设备描述表表示的逻辑意义上的“显示平面”上去。设备描述表是深寓于Windows中的一种设备结构,它包含GDI需要的关于显示平面情况的描述字段,包括相连的物理设备和各种各样的状态信息。在平面上画图之前,Windows程序从GDI获取设备描述表的句柄,并且每次调出GDI输出函数时,将句柄返回给GDI。若没有有效的设备描述表聚丙,则GDI不会画第一个像素。

再利用MFC编制Windows程序时,设备描述表具有更加突出的作用。除了可以作为通往各种输出设备的桥梁之外,设备描述表对象还封装了程序用来产生输出的GDI函数。在MFC中,我们不再需要捕获设备描述表句柄和调用GDI输出函数,至少不用直接捕获和调用,而是通过创建设备描述表对象并调用它的成员函数来画图

2.MFC设备描述表类

在MFC应用程序中获取设备描述表的一种方法是调用CWnd::GetDC(),它返回指向表示Windows设备描述表的CDC对象的指针。在画图完毕时,要用CWnd::ReleaseDC()释放由GetDC()获得到的设备吧、描述表的指针。具体如下面程序所示:

CDC* pdc = GetDC();
//do some drawing
ReleaseDC(pdc);

再这里需要我们注意的是,如果在OnPain处理程序中时,则需要Cwnd::BeginPaint和CWnd::EndPaint分别代替GetDC()和ReleaseDC(),以保证合理地处理WM_PAINT消息:

PAINTSTRUCT PS;
CDC* pDC = BeginPaint( & ps );
//do some drawing
EndPaint( & ps );

为避免要记住获取和释放设备描述表时需要调用的函数(并且为了确保在使用设备描述表的消息处理程序结束时设备描述表能合理的被释放)MFC提供了CDC派生类,具体如下:

专门用途的设备描述表类
类名 描述
 CPaintDC  用于在窗口客户区画图(仅限于OnPaint处理程序)
 CClientDC  用于在窗口客户区画图(除了OnPaint以外的任何程序中)
 CWindowDC  用于在窗口内任意地方画图,包括非客户区
 CMetaFileDC  用于向GDI原文件画图

这些类在设计的时候可直接进行实例化(类是事物的抽象封装,对象是类的具体化)各个类的构造函数和析构函数调用相应的函数捕获和释放设备描述表,从而使得设备描述表的使用非常方便:

CPaintDC dc(this);//该参数传给CPaintDC的类构造函数,确定设备描述表所属的窗口
//do some drawing

当在栈上构造设备描述表对象时,若对象的生命周期结束,则它的析构函数会被自动调用。而且析构函数一旦被调用,设备描述表就会被返回给Windows。在堆上用new创建的设备描述表时,一定要注意亲自释放设备描述表。示例如下:

CPaintDC *pDC = new CPaintDC (this);//堆上创建指向CPaintDC的对象指针
delete pDC;

CPaintDC类:
MFC的CPaintDC类响应WM_PAINT消息,允许在窗口客户区画图。但是,需要注意。我们只能在OnPaint处理程序中使用,不能再其他别的地方应用。WM_PAINT消息有一点与其他Windows消息都不同。如果处理程序调用Windows的::BeginPaint()和::EndPaint函数失败,那么不管有多少绘图工作,都不能将该消息从消息队列中删除。因此,应用程序讲一遍又一遍的处理同一个WM_PAINT消息,这不就陷入死循环了吗?而通过分别从CPaintDC的构造函数和析构函数中调用::BeginPaint和::EndPaint,CPaintDC能保证陷入死循环这种事不发生!

CClientDC和CWindowDC类:

Windows程序不是总将绘图限制在OnPaint上,如果编写一个应用程序,只要以单击鼠标吗,应用程序就在屏幕上画一个圆饼,那么我们就希望在接收到按钮单击消息时就立刻画圆,而不必刻意的去等待WM_PAINT消息。这就是CClientDC存在的价值。CClientDC创建了可以在OnPaint外使用的用户区域设备描述表。下面示例程序使用了CClientDC创建了两个CDC成员函数,来完成了在鼠标左键被单击时画一个X链接串口客户区四角的功能。

void CMainWindow::OnButtonDown( UINT nFlag, CPoint point){
CRect rect;
GetClientRect( & rect );CClientDC dc(this);//传递当前窗口指针
dc.MoveTo(rect.left,rect.top);
dc.LineTo(rect.right,rect.bottom);
dc.MoveTo(rect.right,rect.top);
dc.LineTo(rect.left,rect.bottom);
}

如果我们不仅想使用窗口客户区,还用使用非客户区(标题栏,窗口边框等),这就需要使用CWindowDC类。比如,我们想自己绘制标题栏和带圆角的窗口,大多数情况下CWindowDC并不常用。因为如果我们想在窗口非客户区作图,可以借助OnNcPaint处理程序捕捉WM_NCPAINT消息。

3.设备描述表属性

下面总结一下设备描述表中最常用的属性和访问这些属性所用的CDC函数:

主要的设备描述表属性
Attribute Default Set with Get with
文本颜色 Black CDC::SetTextColor CDC::GetTextColor
背景颜色 White CDC::SetBkColor CDC::GetBkColor
背景模式 OPAQUE CDC::SetBkMode CDC::GetBkMode
映射模式 MM_TEXT CDC::SetMapMode CDC::GetMapMode
绘图模式 R2_COPYPEN CDC::SetROP2 CDC::GetROP2
当前位置 (0,0) CDC::MoveTo CDC::GetCurrentPosition
当前画笔 BLACK_PEN CDC::SelectObject CDC::SelectObject
当前画刷 WHITE CDC::SelectObject CDC::SelectObject
当前字体 SYSTEM_FONT CDC::SelectObject CDC::SelectObject

毫无疑问,对于Windows编程的新手来说,GDI编程中最困难的部分就是映射模式(mapping mode)。映射模式用于确定从逻辑坐标值到设备坐标值的转换方式。传送给CDC输出函数的是逻辑坐标值。设备坐标值是指窗口相应的像素点位置。调用dc.Rectangle(0,0,200,200)函数是,不知告诉GDI画一个200个像素点宽、100个像素点高的矩形,而是告诉它画一个200个单位宽、100个单位高的矩形。在默认映射模式MM_TEXT下,一个像素点钱钱相当于一个单位。

戏说 Windows GDI (1)相关推荐

  1. 戏说 Windows GDI (3)

    继续讨论之前的问题,包括GDI对象的删除问题,窗口注册与销毁问题,最后用标尺的小例子说明问题 1.GDI对象的删除 由CGDIObject派生类创建的画笔.画刷和其他对象都要占用内存资源,因此在使用完 ...

  2. 戏说 Windows GDI (2)

    1. GDI画笔和CPen类 Windows用当前选入设备描述表的画笔绘制直线和曲线,并给用Rectangle.Ellipse以及其他图像生成函数画出的图形镶嵌边框.在系统默认的情况下,画笔是指一个像 ...

  3. MFC和Win32之三___CGdiObject类和windows Gdi对象

    小结: 前面讲到的windows窗口对象,在windows下用句柄来代表之,并且用了一个数据结构WNDCLASS(窗口类)来描述之.同理,windows的Gdi对象也有一些句柄来代表之(比如hPen等 ...

  4. Windows GDI和GDI+编程实例剖析(1)

    Windows GDI和GDI+编程实例剖析(1) 作者:宋宝华  e-mail:21cnbao@21cn.com 1.基本概念 GDI在Windows中定义为Graphics Device Inte ...

  5. 原创]Windows Gdi入门初级应用(VC SDK)

    原创]Windows Gdi入门初级应用(VC SDK) 好久没发贴了,今天手痒痒,发一个. GDI的绘图函数基本上都是有状态的,所有的函数都要求一个HDC类型的句柄. 这个HDC的获得有几个途径Be ...

  6. GetBitmapBits和GetDIBits的区别(Windows GDI)

    Windows GDI中有两个用来得到位图图像数据的API,分别是GetBitmapBits和GetDIBits; 按照MSDN的解释,前者是用来得到设备独立位图的BITS, 后者是得到兼容位图的BI ...

  7. windows GDI+ 绘图的简单封装

    由于用mfc经常需要在界面上进行一些绘制输出,所以用windows GDI比较多,但是用windowsGDI 绘图比较麻烦,刚开始学的时候还经常弄不清一堆DC, Object, HANDLE到底是干啥 ...

  8. Windows GDI

    Windows GDI 在单任务环境如 MS-DOS 中,运行中的应用程序随时可自由地做它想做的事情,无论是在屏幕上画一条线,重新编写适配器的调色板,还是转换到另一种图像模式.而在窗口化多任务环境如 ...

  9. Windows GDI 窗口与 Direct3D 屏幕截图

    前言 Windows 上,屏幕截图一般是调用 win32 api 完成的,如果 C# 想实现截图功能,就需要封装相关 api.在 Windows 上,主要图形接口有 GDI 和 DirectX.GDI ...

最新文章

  1. java udp tcp协议_【java】TCP和UDP传输协议
  2. 为什么大型互联网都需要网关服务?
  3. XMLHttpRequest cannot load解决方案
  4. GetLogicalDrives GetDriveType GetVolumeInformation和FindVolumeClose
  5. SQ 小车避障 Intel Realsense D435 基于线性梯度的深度值过滤
  6. matlab 功率谱密度 汉宁窗_[振动与测试 2] 什么是PSD(功率谱密度)
  7. 腾讯视频手机app下载安装_腾讯视频怎么签到
  8. 快速判断二叉树先序遍历 后序遍历
  9. Visual Studio 2013 突然不高亮,编译报错
  10. 阶段3 1.Mybatis_11.Mybatis的缓存_8 mybatis的二级缓存
  11. centos6 挂载ntfs格式移动硬盘
  12. 搜索引擎自动提交连接php文件,死链检测工具(自动提交给百度,逆天了)
  13. word流程图怎么做虚线框_Word2016如何制作虚线文本框?
  14. 大数据处理的四大步骤
  15. 大白话图解:什么是 CDN
  16. Microsoft Edge逃离360之路
  17. mysql 汉字笔画排序规则_SQL Server 与 MySQL 中排序规则与字符集相关知识的一点总结...
  18. 作为一个新手程序员该如何成长
  19. quartz报错:Couldn‘t retrieve trigger: No record found for selection of Trigger with key—————————————
  20. 基于Python企业公司网站设计与实现 开题报告

热门文章

  1. wifi拥挤时防掉线小技巧
  2. 条件语句:case语句
  3. linux下dhcp配置(一)
  4. hdu 5265(二分+枚举)
  5. hdu 3987(最小割的边数)
  6. poj 1981(单位圆覆盖点)
  7. nyoj1311勤奋的涟漪
  8. NYOJ练习题 删除元素(二分查找)
  9. 使用Vue.js初次真正项目开发-2018/07/14
  10. Python - 按天算年龄