张丹丹
摘 要:Vc++是微软推出的面向对象的可视化集成编程系统,随Visual C++的发布还包括MFC-微软基础类,MFC提供的类很多用于界面开发,并设计了合理的消息映射机制和相应的消息处理函数,实现设备环境绘图等。
中图分类号:TP3 文献标识码:A 文章编号:1674-098X(2012)07(c)-0004-02
1 引言
,是经典的windows视窗和windows应用程序的开发平台。为了减少程序设计人员工作开发量它提供有效的应用程序框架,对类进行了封装,大部分是从Cobject里派生而来的,包含窗口类、图形设备接口类、对象链接和嵌入类、文件和数据库类、输入/输出类、异常类等等。
利用MFC提供的类我们可以方便做出一些不规则形状的界面,同时利用双缓冲原理有效解决界面抖动或界面显示慢的问题。当窗口被改变大小,被最小最大化,或被关闭再打开,或者被另一个窗口覆盖的时候,窗体都面临着重绘,于是Window触发WM_PAINT消息处理复杂图形的绘制,由于过多的刷频导致图形显示出抖动、缓慢等症状,利用内存设备环境,具体归纳为双缓冲技术,可以有效解决这一问题。
2 MFC提供的设备环境类
MFC提供的类很多用于界面开发,其中一个重要的类—CDC,提供了处理设备环境,如显示器、打印机等设备的成员函数。MFC将GDI(图形设备接口)封装在CDC类中,因此可以调用该类成员函数完成诸如各种颜色、尺寸,不同图形的绘图操作,同时GDI具有设备无关性,程序员也无需考虑设备的类型。CDC的这种设备无关性,使Windows下的绘图等程序不直接面向物理设备,而通过虚拟的设备描述表进行。
设备描述表又称设备上下文或设备环境,它是一种Windows下的数据结构,它存储了设备绘图属性信息。应用程序不能直接访问设备描述表,只能由各种相关API函数通过设备描述表的句柄间接访问该结构。MFC提供的DC类包括CDC类和其派生类:CwindowDC、CclientDC 、CpaintDC等等,这些类都封装了HDC句柄。CpaintDC是OnPaint()函数使用的设备环境类,该类对象只在响应WM_PAINT消息时调用,WM_PAINT是窗口每次重绘都会产生的一个消息, 而OnPaint()是对这个消息的响应函数,通常在使用OnPaint()函数处理WM_PAINT消息时,就可以创建一个CpaintDC类对象。CclientDC在处理非WM_PAINT消息时使用,用于绘制客户区。另外还有很多DC类它们对于输出的效果、图形的颜色、剪裁、绘制等同样发挥各自的作用。
另外一类重要的DC为内存DC, 它是虚拟的设备环境,可以有效的解决绘图在显示中所出现闪烁或缓慢的现象,也为双缓冲技术的基本要点,实现步骤为:1)为当前的设备环境创建相匹配的内存DC,可以调用CreateCompatibleDC()函数实现;2)创建或导入位图,可以调用Create Compatible Bitmap() 、LoadBitmap、LoadImage()等函数;3)将位图载入内存设备环境,利用函数SelectObject()实现;4)将内存设备环境中绘制好的图像拷贝至物理设备环境,利用BitBlt()完成。同时注意:当建立多个内存DC时,应将每个内存DC的绘图一同复制到另一个内存DC中,再把这个复制好的内存DC拷贝至物理设备环境中。
3 MFC制作特殊界面和双缓冲技术的实例
(1)窗口形状的显示在对话框初始函数中设置(代码如下):
BOOL CEllipsefaceDlg :: OnInitDialog()
{
CDialog :: OnInitDialog() ;
......\此出代码省略
CRgn a ;// 创建CRgn类对象a
a.CreateRoundRectRgn (0, 0, 400, 400, 700, 700 )[A1] ;
SetWindowRgn ( ( HRGN ) a,true )[A2] ; }(如图1)
代码详解:
1.CRgn类封装了一个Windows图形设备接口(GDI)区域,调用CRgn类的成员函数可实现椭圆或者特殊矩形界面。
CRgn成员举例说明:
CreateEllipticRgn():初始化一个椭圆区域的CRgn类对象
CreateRoundRectRgn(x1,y1,x2,y2,x3,y3):初始化一个圆角矩形区域的CRgn类对象
参数说明:
x1,y1:左上角x轴和y轴坐标
x2,y2:右下角x轴和y轴坐标
x3,y3:用于创建圆角的椭圆,它的宽度和高度
2.SetWindowRgn(HRGN hRgn,BOOL bRedraw):该函数用于设置窗口区域,该窗口区域决定了系统允许绘制窗口的范围,超出该窗口区域的范围系统一律不显示。
参数说明:
HRGN hRgn:指向一个区域的句柄,把窗口设置在该区域。如果此参数设为NULL,函数不设置窗口区域。
BOOL bRedraw:参数为true,操作系统在设定区域后重新绘制窗口,反之不。
* 图片显示在OnPaint()函数中设置(代码如下):
void CEllipsefaceDlg :: OnPaint()
{ …… // 此处代码省略
else
{ ① CPaintDC dc ( this ) ;
② CRect area ;
GetWindowRect ( &area ) ;
③ CBitmap cBitmap ;
CBitmap * pOldMemBmp = NULL ;
cBitmap.LoadBitmap ( IDB_BITMAP ) ;
④ CDC mdc ;
mdc.CreateCompatibleDC(&dc);
⑤ pOldMemBmp = mdc.SelectObject ( &cBitmap ) ;
⑥ dc.BitBlt(0, 0, area.Width(), area.Height(), &mdc, 0, 0,SRCCOPY ) ;
⑦ if ( pOldMemBmp )mdc.SelectObject ( pOldMemBmp ) ;
CDialog :: OnPaint() ;
}
}
代码详解(如图2):
①CPaintDC:派生于CDC的设备环境类。该类是OnPaint()函数使用的DC类,因此首先创建一个类对象dc。
②CRect类:RECT结构的数据成员(left,top,right,and bottom)也是CRect的可访问的数据成员。在任何传递RECT结构,LPCRECT或LPRECT的函数中,都可以将一个CRect对象作为函数参数来代替。
void GetWindowRect(LPRECT lpRect) :属于CWnd类的成员函数,返回窗口的边框尺寸。
参数解释:
const,lpRect,指向一个RECT结构的指针,该结构接收窗口的左上角和右下角的屏幕坐标。
总结:这两行代码利用GetWindowRect()获取窗口区域,该函数参数为指向RECT结构的指针,因此首先创建一个Crect类对象area。
③CBitmap类封装了窗口图形设备接口位图,提供操作位图的成员函数。使用CBitmap对象之前要先构造CBitmap对象,调用其中的一个初始化成员函数设置位图对象的句柄,本段程序调用了LoadBitmap(),此后就可以调用其它成员函数了。
LoadBitmap:从模块的可执行文件中加载已命名的位图资源,用来初始化对象,并且把位图贴到对象中。本例中该函数参数为插入背景位图的ID。
④创建CDC类的对象mdc(内存设备环境)。
CDC:定义了一类设备环境对象,所有的绘画可以通过CDC的成员函数完成,该类提供了为设备环境操作的成员函数,比如绘画工具的使用,使用颜色和调色板,窗体范围的使用,转换坐标,剪裁绘制线条,绘制简单图形等,该类还提供文本设置等的函数。在写有关图形界面的程序时,需使用CDC类及其子类。
CreateCompatibleDC:创建一个与物理设备兼容的内存设备环境,可以使用该内存设备环境在内存中存放图片。此例调用该函数创建相应的内存设备环境mdc。
总结:利用双缓冲技术的基本点是创建与设备坏境相对应的内存DC。
⑤CGdiObject* SelectObject( CGdiObject* pObject ):选择一个图形设备界面对象到指定的设备环境中,新的对象会替换掉之前的同类对象;
参数解释:
hdc:设备上下文环境的句柄。
hgdiobj:被选择的对象的句柄,该指定对象必须由如下的函数创建。
总结:为指向旧的内存位图设置一个CBitmap类的指针,并预先设置该指针为空。然后将该指针指向载入位图的内存设备坏境。
⑥BitBlt:把设备环境源的位图复制到当前设备环境中。这里指把内存设备环境的位图复制到当前的物理设备环境中,本例中即显示器。
参数设置:
HDC hDestDC:指向目标设备环境的HDC句柄
xDest:目标矩形左上角的逻辑x轴坐标
yDest:目标矩形左上角的逻辑y轴坐标
pointDest:显示目标矩形做上角的点结构
nDestWidth:目标矩形的逻辑宽度
nDestHeight:目标矩形的逻辑高度
HDC hSrcDC:指向源设备环境的HDC句柄
xSrc:源矩形左上角的逻辑x轴坐标
ySrc:源矩形左上角的逻辑y轴坐标
dwrop:执行栅格操作
rectDest:显示目标区域的rect结构
pointSrc:显示源矩形左上角的点结构
⑦ 如果指向内存位图的指针不为空,则将其指向的位图选入内存设备环境中。
(2)拖动窗体在WM_LBUTTONDOWN消息中实现(代码如下):
void CEllipsefaceDlg::OnLButtonDown ( UINT nFlags,CPoint point )
{
::SendMessage ( this->GetSafeHwnd(), WM_SYSCOMMAND, SC_MOVE+2, 0 ) ;
CDialog :: OnLButtonDown ( nFlags,point ) ;
}
代码详解:
LRESULT SendMessage( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam
):
为指定的窗口唤醒窗口程序,然后发送指定的消息给该窗口,当唤醒的窗口程序处理完消息后返回。
参数解释:
HWND hWnd:指向唤醒窗口程序且将接受消息的窗口的句柄。
UINT Msg:被发送的指定消息。
WPARAM wParam、 LPARAM lParam :指定系统命令的类型。他们的类型可以是:SC_CLOSE(关闭窗口)、SC_HOTKEY(以应用程序指定的热键激活窗口)、SC_MAXIMIZE(最大化窗口)、SC_MOVE(移动窗口)等。
CWnd::GetSafeHwnd:返回一个窗口的窗口句柄。
WM_SYSCOMMAND:当用户从窗口菜单中选择一个命令时,比如选择最大化、最小化、还原、关闭等按钮的时候,这些消息被发送至该窗口。
4 结语
本文通过窗口类、图形设备接口类、设备上下文的成员函数及其类的创建和使用,阐述了如何使用MFC简便的绘制不规则矩形界面,以及如何使用双缓冲技术的原理和模式用于提高界面显示效果等内容。对于MFC的消息及设备上下文的学习,可以探索出更多知识及应用。
参考文献
[1] 刘锐宁,梁水,宋坤.Visual C++程序开发范例宝典[M].北京:人民邮电出版社,2009.
[2] 姚领田,高守传.MFC窗口程序设计[M].北京:中国水利水电出版社,2007.
[3] G.(Shepherd,George),S.(Wingo.Scot).深入解析MFC.北京:中国电力出版社,2003.
[4] Microsoft.MSDN库(中文) [DB/OL]. http://msdn.microsoft.com/library,2012/2012-05-03.
[5] 尹立民,王兴东.Visual C++软件项目开发实例[M].北京:电子工业出版社,2004.
[A1]对象a调用CRgn类成员函数CreateRoundRectRgn(),被初始化为一个圆角区域。
[A2]将初始化后的对象a作为对象句柄放入SetWindowRgn()中做参数,刚刚创建的圆角区域被设置为窗体区域,SetWindowRgn()为CWnd的成员函数。