本文主要是介绍戏说 Windows GDI (1),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
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()获得到的设备吧、描述表的指针。具体如下面程序所示:
再这里需要我们注意的是,如果在OnPain处理程序中时,则需要Cwnd::BeginPaint和CWnd::EndPaint分别代替GetDC()和ReleaseDC(),以保证合理地处理WM_PAINT消息:CDC* pdc = GetDC(); //do some drawing ReleaseDC(pdc);
为避免要记住获取和释放设备描述表时需要调用的函数(并且为了确保在使用设备描述表的消息处理程序结束时设备描述表能合理的被释放)MFC提供了CDC派生类,具体如下:PAINTSTRUCT PS; CDC* pDC = BeginPaint( & ps ); //do some drawing EndPaint( & ps );
专门用途的设备描述表类 类名 描述 CPaintDC 用于在窗口客户区画图(仅限于OnPaint处理程序) CClientDC 用于在窗口客户区画图(除了OnPaint以外的任何程序中) CWindowDC 用于在窗口内任意地方画图,包括非客户区 CMetaFileDC 用于向GDI原文件画图 这些类在设计的时候可直接进行实例化(类是事物的抽象封装,对象是类的具体化)各个类的构造函数和析构函数调用相应的函数捕获和释放设备描述表,从而使得设备描述表的使用非常方便:
当在栈上构造设备描述表对象时,若对象的生命周期结束,则它的析构函数会被自动调用。而且析构函数一旦被调用,设备描述表就会被返回给Windows。在堆上用new创建的设备描述表时,一定要注意亲自释放设备描述表。示例如下:CPaintDC dc(this);//该参数传给CPaintDC的类构造函数,确定设备描述表所属的窗口 //do some drawing
CPaintDC类:CPaintDC *pDC = new CPaintDC (this);//堆上创建指向CPaintDC的对象指针 delete pDC;
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链接串口客户区四角的功能。
如果我们不仅想使用窗口客户区,还用使用非客户区(标题栏,窗口边框等),这就需要使用CWindowDC类。比如,我们想自己绘制标题栏和带圆角的窗口,大多数情况下CWindowDC并不常用。因为如果我们想在窗口非客户区作图,可以借助OnNcPaint处理程序捕捉WM_NCPAINT消息。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); }
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)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!