MFC Windows程序设计 读书笔记2

Windows中负责图形输出的是Graphics Device Interface(图形设备接口),或称GDI。本节主要讲述CDC类和它的继承类,并介绍三种最常用的GDI基本元素,画笔、画刷、和字体,同时还将示范如何在窗口中添加滚动条。

Windows GDI

在窗口化、多任务的Windows环境中,各个应用程序的输出必须限制到自己窗口上,做到互不干扰,GDI使用以简单的机制来保证在窗口中的画图程序遵循这一规则,这种机制即为设备描述表(DC)。在平面上画图之前,Windows程序从GDI获取设备描述表句柄,并每次调用GDI的输出函数时候将句柄返回给GDI,获得设备描述表句柄后,同一GDI函数可用来向多种输出设备上画图。

如何理解设备描述表?

GDI是Graphics Device Interface的缩写,含义是图形设备接口,它的主要任务是负责系统与绘图程序之间的信息交换,处理所有Windows程序的图形输出。
在Windows操作系统下,绝大多数具备图形界面的应用程序都离不开GDI,我们利用GDI所提供的众多函数就可以方便的在屏幕、打印机及其它输出设备上输出图形,文本等操作。GDI的出现使程序员无需要关心硬件设备及设备驱动,就可以将应用程序的输出转化为硬件设备上的输出,实现了程序开发者与硬件设备的隔离,大大方便了开发工作。

设备描述表是一个定义一组图形对象及其属性、影响输出的图形方式(数据)结构。windows提供设备描述表,用于应用程序和物理设备之间进行交互,从而提供了应用程序设计的平台无关性。设备描述表又称为设备上下文,或者设备环境。
设备描述表是一种数据结构,它包括了一个设备(如显示器和打印机)的绘制属性相关的信息。所有的绘制操作通过设备描述表进行。设备描述表与大多WIN32结构不同,应用程序不能直接访问设备描述表,只能由各种相关API函数通过设备描述表的句柄间接访问该结构。

GDI是如何实现输出的? 

要想在屏幕或者其它输出设备上输出图形或者文字,那么我们就必须先获得一个称为设备描述表( DC:Device Context)对象的句柄,以它为参数,调用各种GDI函数实现各种文字或图形的输出。设备描述表是GDI内部保存数据的一种数据结构,此结构中的属性内容与特定的输出设备(显示器,打印机等)相关,属性定义了GDI函数的工作细节,在这里属性确定了文字的颜色,x坐标和y坐标映射到窗口显示区域的方式等。
 设备描述表句柄一旦获得,那么系统将使用默认的属性值填充设备描述表结构。
 如果有必要,我们可以使用一些GDI函数获取和改变设备描述表中的属性值。
在使用MFC编写Windows程序时,设备描述表具有更加突出的作用,除了可作为通向各种输出设备的桥梁之外,设备描述表对象还封装了程序用来产生输出的GDI函数,在MFC中,你不用捕获设备描述表句柄或者是调用GDI输出函数,至少不用直接捕获或者是调用,而是通过创建以设备描述表对象并通过其成员函数来画图。
MFC的CDC类将Windows设备描述表和获取设备描述表句柄的GDI函数就近封装在一起,而CDC派生类如CPaintDC和CCLientDC则代表Windows的应用程序使用不同的类型。
参考博客:http://blog.163.com/efjing@126/blog/static/424848482008102711235165/

MFC设备描述表类

获取MFC设备描述表:

CDC * pDC = GetDc();
////do some drawing;
RelaseDC(pDC);

通过调用CDC::GetDc()来获取设备描述表,它返回一个指向CDC对象的指针,在画图完毕后,要调用 CDC::RelaseDC()来释放由CDC::GetDc()获取的设备描述表指针。

同样的代码出现在OnPaint处理程序中时,则需用CWnd::BeginPaint()以及CWnd::EndPaint()分别代替CDC::GetDc()以及 CDC::RelaseDC(),以保证其合理的处理WM_PAINT消息。

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

为了避免要记住捕获设备描述表或者是释放描述表时候所要调用的函数,MFC提供了一些CDC派生类,这些类被设计为可直接进行实例化,各个类的构造函数与析构函数调用相关函数捕获或者释放响应的设备描述表函数。

类名 描述
CPaintDC 用于在窗口客户区画图(仅限于OnPAint处理程序)
CClientDC 用于在窗口客户区画图(除OnPAint以外的任何处理程序)
CWindowDC 用于在窗口内任何地方画图,包括非客户区
CMetaFileDC 用于向GDI源文件画图

CPaintDC类
MFC的CPaintDC类响应WM_PAINT消息,允许您在窗口客户区画图,但您只能在OnPAint处理程序中使用它。
CClientDC类
创建了可以在OnPaint区域外使用的用户区域设备描述表。
CWindowDC类
描绘了包括窗口边框的所有内容,如标题栏等

设备描述表属性

这里写图片描述

最常用来定义设备描述表属性的CDC函数是SelectObject,下面所列的是6个GDI对象,可由SelectObject选入设备描述表。

  1. 画笔(Pen)
  2. 画刷(Brush)
  3. 字体(Font)
  4. 位图(Bitmap)
  5. 调色板(Palette)

    在MFC中,CPen,CBrush,CFont分别代表了画笔,画刷与字体。除非调用SelectObject以改变当前画笔、画刷或者是字体,否则GDI将使用设备描述表当中的默认值。

映射坐标系

毫无疑问,对于GDI编程新手来说,GDI编程中最困难的部分便是映射模式(mapping mode),简单的说,映射模式是设备描述表的属性,用于确定从逻辑坐标值到设备坐标值的转换方式:

这里写图片描述

在MM_TEXT映射模式下画图时,所使用的坐标系,原点在窗口左上角,X轴正向向右,Y轴正向向下,并且一个单位相当于一个像素点,如果使用其它映射模式,则Y轴会翻转正向向上,逻辑单位按照比例转化为实际距离的大小,而不是像素。
如果在向非MM_TEXT映射模式下转换时,应用程序通常不见了,那么请检查Y轴坐标值的正负号,一般问题总是出现在Y上。
例如:

在MM_TEXT映射模式下画一个200个像素点宽,100个像素点长的矩形。

dc.Rectangle(0,0,200,100)

但这个语句在MM_LOENGLISH映射模式下却订不到输出,这是因为正的Y坐标值不在窗口的可见部分。如果想要矩形显示出来,应该把Y修改成负值:

dc.Rectangle(0,0,200,-100)

画直线和曲线

MFC的CDC类中包含了很多用来画直线和曲线的成员函数下表列出了一些关键的函数:

这里写图片描述

例如:画直线

调用LineTo()函数并给出另一个点的坐标即可:

dc.MoveTo(0,0);
dc.LineTo(0,100);

如果想再画一条直线的话,我们只需要再次调用LineTo(),由于第一次调用LineTo()的时候当前位置已经设置为此直线的终点,我们只需要继续调用LineTo()即可。

dc.MoveTo(0,0);
dc.LineTo(0,100);
dc.LineTo(100,100);

当然,GDI不会简单的把你限制在直线和曲线上,它还允许你画椭圆、矩形、饼状楔形物等等,MFC的CDC类将相关的GDI函数封装在类的成员函数中,具体如下表所示:

这里写图片描述

例如:画圆
在用Ellipse函数画圆的时候,我们不需要指出圆的原点以及半径,而是要指出其外接边框

dc.Ellipse(0,0,100,100);

或者通过Rect结构或者是CRect对象来传送

CRect Rect(0,0,100,100);
dc.Ellipse(Rect);

GDI画笔和CPen类

默认画笔画出的是一个像素宽的黑色实线,如果我们不想要默认的属性,则需要创建一个GDI画笔,并由CDC::SelectObject()将其选入设备描述表。
MFC用CPen表示GDI画笔,创建画笔最简单的方法就是构造一个CPen对象并且把画笔的相关参数传递给该对象,具体代码示例如下:

CPen pen(PS_SOLID,1,RGB(255,0,0));

还有一种方法是构造一个没有初始化的CPen对象,像LOGPEN结构中添加描述画笔特性的参数,然后调用CPen::CreatPenIndirect生成画笔,具体示例代码如下:

CPen pen;
LOGPEN lp;
lp.lopnStyle = PS_SOLID;
lp.lopnWidth.x = 1;
lp.lopnColor = RGB(255,0,0);
pen.CreatPenIndirect(&lp);

具体可选的画笔样式为:

这里写图片描述

画文本

我们知道,CDC::DrawText()函数往显示屏幕上写一串文本,在制定格式化矩形以及一系列指示矩形中文本位置的选项标志后,DrawText就知道往哪里画它的输出了。
例如前面介绍的hello程序:

dc.DrawText(_T("Hello MFC"),-1,&rect,DT_SINGLELINE|DT_CENTER|DT_VCENTER);

rect是用窗口客户区坐标值初始化的矩形对象,而DT_CENTER和DT_VCENTER则告诉DrawText将内容输出到矩形的中部。
DrawText是CDC类中与文本输出有关的函数之一,如下表所示:
这里写图片描述

其中最有用的一个函数是Textout,与DrawText一样,它能够输出文本,但是不同的是,它要接受一组X-Y坐标来指定文本输出位置,如果有要求它也可以使用当前位置:

dc.Textout(0,0,CString(_T("Hello,MFC")));

在默认的情况下,传递给Textout,TabbedTextout等的坐标值都确定了文本中最左侧字符左上角位置,但是传给Textout中的坐标值与输出字符串字符位置之间的位置关系,即所谓的文本对齐方式,是设备描述的一个属性,我们可以通过调用相关的函数来修改这一个属性。用户可调用CDC::SetTextAlign来实现相应的功能。

//表示右对齐文本
dc.SetTextAlign(TA_RIGHT);

GDI字体与CFont类

所有的CDC文本函数都使用当前选入设备描述表的字体,与画笔与画刷一样,字体也是一个GDI对象,在MFC中,字体由CFont类对象来表示,构造了CFont对象之后,就可以调用相关函数修改属性。
在传统的印刷样式中,字体的大小是以point即点为单位来衡量的,一个点相当于1/72英寸高,12点字体中的字符就有1/6英寸高。
我们用CFont的CreatePointFont()函数创建一个12点屏幕字体只需要两行代码:

CFont fontfont.CreatePointFont(120,_T("Times New Roman"))

注意:传递给CreatePointFont()的数值是你所期望点的大小的10倍,这样字体的尺寸就可控制在点的1/10,对于大部分场合,这个精度已经足够用了。

删除GDI对象

由CGI派生类创建出来的画笔,画刷等其他对象都要占用内存资源,那么在使用完毕之后一定要删除它们,以释放内存。
试想如果每次在调用OnPint()处理程序都要创建十个画笔和画刷,但又没能删除它们,那么会发生什么事情呢?过了一段时间之后,可能对创建成千上万个GDI对象,占据着WindowsGDI的系统内存空间,很快,创建画笔和画刷的调用会失败,OnPint()程序也会莫明奇妙的停止工作。

猜你喜欢

转载自blog.csdn.net/godqiao/article/details/78531327
今日推荐