GDI编程绘图.docx
《GDI编程绘图.docx》由会员分享,可在线阅读,更多相关《GDI编程绘图.docx(42页珍藏版)》请在冰豆网上搜索。
![GDI编程绘图.docx](https://file1.bdocx.com/fileroot1/2023-1/10/861153ea-c357-4eb2-a273-5e55ea87b7b4/861153ea-c357-4eb2-a273-5e55ea87b7b41.gif)
GDI编程绘图
第8章GDI编程1-绘图
详细介绍了GDI绘图,希望对你有帮助:
GDI(GraphicsDeviceInterface,图形设备接口)是Windows操作系统的传统图形子系统,负责与设备无关的图形绘制,Win32API为应用程序提供了丰富的绘图函数和功能,MFC对它们进行了C++类封装,参见图8-1。
Windows应用程序
MFC
Win32API
执行程序
用户界面(User)
GDI+
图形子系统(GDI)
设备驱动程序
内核(Kernel)
图形驱动程序
硬件抽象层(HAL)
计算机硬件
图8-1GDI与Windows操作系统(其中彩色部分为操作系统)
传统GDI是随Windows1.0于1985年11月推出的,新式GDI+则是随WindowsXP于2001年10月推出的GDI的改进版,增加了α混色、渐变画刷、样条曲线、矩阵变换、图像处理、持久路径等新功能。
随WindowsVista及.NET框架3.0微软于2006年11月又推出了基于DirectX和.NET框架的全新图形子系统WPF(WindowsPresentationFoundation,视窗显示/展现基础),它统一了桌面和浏览器等客户端应用程序的图形界面,采用XAML声明式编程,将用户界面的设计和编程彻底分离开来,是Windows的下一代GUI显示系统。
本书从第8章到第11章,将详细讨论如何使用GDI进行传统的Windows图形编程,包括绘图、文字、图像、动画、图标、图元文件和打印等内容。
GDI+是建立在GDI之上的,计划在第14和15章中作简单介绍。
WPF则是以.NET框架为基础的,准备在第19上和20章中再加以讨论。
在MFC应用程序中,绘图一般在视图类的(屏幕/打印机)绘图消息响应函数OnDraw中进行,例如:
voidCDrawView:
:
OnDraw(CDC*/*pDC*/){
CDrawDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
if(!
pDoc)
return;
//TODO:
在此处为本机数据添加绘制代码
}
每次需要重绘窗口时(如程序启动、窗口大小改变、全部或部分窗口重现、程序员调用函数RedrawWindow或Invalidate/UpdateWindow),应用程序框架都会调用此CWnd消息响应成员函数(的覆盖)来绘制窗口客户区。
在Windows中,绘图一般在框架窗口的客户区(对应于视图类C*View)进行,使用的是封装在MFC的设备上下文(Device-Context,DC)类CDC中的各种绘图函数。
在绘图前,一般需先得到客户区大小和CDC对象、设置绘图颜色,然后再根据文档数据或用户操作来绘制各种图形。
8.1几何对象的结构和类
图8-2GDI几何对象的结构与类
为了使用绘图函数,应该先了解绘图所用到的几种表示几何对象的结构和类,包括点、大小和矩形,其中常用的是点和矩形。
这些结构和类被分别定义在头文件windef.h和afxwin.h中。
MFC中的几何对象类都是独立的类(不是CObject的派生类),是对API中对应结构的C++封装,参见图8-2。
8.1.1点
点(point)在API中的结构为POINT,对应的MFC类为CPoint。
1.点结构POINT
API中的点数据结构POINT用来表示一点的x、y坐标:
typedefstructtagPOINT{LONGx;LONGy;}POINT;
其中,类型LONG(32位整数)的定义为:
typedeflongLONG;
2.点类CPoint
MFC中的点类CPoint为一个没有基类的独立类,封装了POINT结构,有成员变量x和y,其构造函数有5种:
CPoint();//默认
CPoint(intinitX,intinitY);//常用
CPoint(POINTinitPt);
CPoint(SIZEinitSize);
CPoint(LPARAMdwPoint);//低字设为x、高字设为y
CPoint类还定义了4个平移和设置的成员函数:
voidOffset(intxOffset,intyOffset);
voidOffset(POINTpoint);
voidOffset(SIZEsize);
voidSetPoint(intX,intY);
另外,CPoint类还重载了+、-、+=、-=、==、!
=等运算符来支持CPoint对象和CPoint、POINT、SIZE对象之间的运算。
8.1.2大小
大小(size,尺寸)在API中的结构为SIZE,在MFC中的类为CSize。
1.大小结构SIZE
大小结构SIZE用来表示矩形的宽cx和高cy:
typedefstructtagSIZE{LONGcx;LONGcy;}SIZE;
2.大小类CSize
MFC中的大小类CSize也为一个没有基类的独立类,封装了SIZE结构,有成员变量cx和cy,其构造函数也有5种:
CSize();
CSize(intinitCX,intinitCY);
CSize(SIZEinitSize);
CSize(POINTinitPt);
CSize(DWORDdwSize);//低字设为cx、高字设为cy
CSizet类也重载了+、-、+=、-=、==、!
=等运算符来支持CSize对象和CSize、POINT、SIZE、RECT对象之间的运算。
8.1.3矩形
矩形(rectangle)在API中的结构为RECT,在MFC中的类为CRect。
1.矩形结构RECT
API中的矩形结构RECT定义了矩形的左上角与右下角的坐标:
typedefstructtagRECT{LONGleft;LONGtop;LONGright;LONGbottom;}RECT;
2.矩形类CRect
MFC中的矩形类CRect也为一个没有基类的独立类,封装了RECT结构,有成员变量left、top、right和bottom,其构造函数有6种:
CRect();//默认
CRect(intl,intt,intr,intb);//常用
CRect(constRECT&srcRect);
CRect(LPCRECTlpSrcRect);
CRect(POINTpoint,SIZEsize);
CRect(POINTtopLeft,POINTbottomRight);
CRect类重载了=,+、-,+=、-=,==、!
=,&、|,&=、|=等运算符来支持CRect对象和CRect、POINT、SIZE、RECT对象之间的运算。
还定义了转换符LPCRECT和LPRECT来自动完成CRect对象到矩形结构和类指针LPCRECT和LPRECT的转换。
CRect类中常用的属性和成员函数有:
intWidth()const;
intHeight()const;
CSizeSize()const;
CPoint&TopLeft();
CPoint&BottomRight();
CPointCenterPoint()const;
voidSwapLeftRight();
BOOLIsRectEmpty()const;
BOOLPtInRect(POINTpoint)const;
voidSetRect(intx1,inty1,intx2,inty2);
voidSetRect(POINTtopLeft,POINTbottomRight);
voidOffsetRect(intx,inty);
voidMoveToXY(intx,inty);
3.判断点是否在矩形中
有时需要判断某点(如鼠标位置)是否在某一矩形区域(如控件)中,这可以调用CRect类的PtInRect函数来做:
BOOLPtInRect(POINTpoint)const;
该函数当点point在其矩形区域内时,返回真。
注意,该矩形区域不包括矩形的右边界和底边界。
例如:
CRectrect(10,10,371,267);
voidCDrawView:
:
OnLButtonUp(UINTnFlags,CPointpoint)
{
//TODO:
在此添加消息处理程序代码和/或调用默认值
if(rect.PtInRect(point))......
CView:
:
OnLButtonUp(nFlags,point);
}
8.1.4获得客户区大小
绘图一般都是在框架窗口的客户区(对应于视图类)进行,而客户区的大小在运行时可由用户动态改变,为了使绘制的图形能随窗口大小而自动改变,需先得到当前客户区大小的数据(宽和高)。
获取客户区大小的方法有如下两种:
1.OnSize
获取客户区大小的第一种方法是通过消息响应函数OnSize中获得。
可利用属性窗口的消息页,为视图类添加WM_SIZE消息的响应函数OnSize。
该函数会在窗口第一次显示或窗口大小被改变时被系统调用。
其输入参数中的cx和cy就是当前客户区的宽和高,可将它们赋值给类变量(如m_iW和m_iH)供绘图时使用。
例如:
voidCDrawView:
:
OnSize(UINTnType,intcx,intcy){
CView:
:
OnSize(nType,cx,cy);
//TODO:
在此处添加消息处理程序代码
m_iW=cx;m_iH=cy;
}
其中,nType的值为:
●SIZE_MAXIMIZED(窗口已被最大化)
●SIZE_MINIMIZED(窗口已被最小化)
●SIZE_RESTORED(窗口已被改变大小)
●SIZE_MAXHIDE(其他窗口被最大化)
●SIZE_MAXSHOW(其他窗口从最大化还原)
2.GetClientRect
获取客户区大小的第二种方法是调用窗口类的获取客户区矩形成员函数GetClientRect来得到。
具体做法是,在绘图前定义一个矩形结构变量rect,然后再调用CWnd类的成员函数GetClientRect来得到当前客户区矩形的数据,该函数的原型为:
voidGetClientRect(LPRECTlpRect)const;
其中,矩形结构的右(right)与底(bottom)就是客户区的宽与高(其左left与顶top都为0)。
例如:
RECTrect;
GetClientRect(&rect);
intiW=rect.right,iH=rect.bottom;
8.2绘图环境DC
在Windows中,绘图包括绘制图形、显示位图和输出文字,它们都需要使用绘图环境DC(Device-Context,设备上下文)。
MFC将DC结构和所有的绘图函数、绘图对象的访问函数、绘图模式与参数的设置函数都封装到了CDC类中。
8.2.1DC结构
DC是Windows为设备无关的图形绘制而定义的一种数据结构,包含了一组图形对象及关联属性和若干影响输出的图形模式和绘图参数。
所有的GDI绘图操作,都是采用DC中的当前图形对象作为绘图工具,并且都是在DC中的当前图形模式下使用当前的绘图参数进行的。
1.图形对象
Windows的图形对象(graphicobject)包括画线状图的笔、绘制和填充面状图的刷、用于复制和滚动部分屏幕的位图、定义可用颜色的调色板、用于裁剪和其他操作的区域、用于绘制和画图操作的路径、及用于输出文字的字体,参见表8-1。
图像对象所对应的MFC类将在8.3.6中介绍,其中笔和刷在8.3.3和8.3.4中介绍,字体在9.2中介绍。
表8-1图形对象及DC的默认值
图形对象
关联属性
DC默认值
笔
风格、宽度、颜色
实心、单像素、黑色
刷
风格、颜色、图案、原点
实心、白色、单色、(0,0)
位图
大小(字节)、尺寸(像素)、颜色格式、压缩方式等
无
调色板
颜色与大小(或颜色数)
20种标准系统色
区域
定位与尺寸
窗口矩形
路径
形状
无
字体
字体名、宽、高、粗细、字符集等
system(宋体)、7、16、700(粗体)、GB2312_CHARSET
2.图形模式
图形模式(graphicsmode)用于确定颜色如何混合、输出在何处出现、输出如何缩放等,参见表8-2。
表8-2图形模式及DC的默认值
图形模式
描述
DC默认值
介绍章节
映射
定义图形输出如何从逻辑(或世界)空间映射到窗口、屏幕或打印机纸,即坐标体系
文本(MM_TEXT),即设备坐标(单位为像素、x向右、y向下)
8.4.1
绘图
对笔、刷、位图和文本操作,定义前景色如何与已存在的窗口或屏幕颜色混合
覆盖(R2_COPYPEN)
8.5.2
背景
对位图和文本操作,定义背景色如何与已存在的窗口或屏幕颜色混合
不透明(OPAQUE)
8.5.1
拉伸
定义在位图被压缩(或缩小)时,定义位图颜色如何与已存在的窗口或屏幕颜色混合
存黑去白(BLACKONWHITE)
9.3.3
多边形填充
定义刷图案如何用来填充复杂区域的内部
交替(ALTERNATE),即按奇偶规则填充
8.5.3
3.图形参数
除了图形对象和图形模式外,DC中还保存有当前的笔位置(默认值为坐标原点)、背景色(默认为白色)、文本色(默认为黑色)、文本对齐(默认为左顶)、画弧方向(逆时针)等绘图参数。
虽然DC是一种结构,但是Windows不允许应有程序的代码直接访问它。
程序员必须通过调用各种对应的Set*和Get*函数以及Select*来设置和获取其中的对象、模式和参数。
8.2.2CDC类
CDC类是MFC对DC结构及其相关绘图和状态设置函数的C++类封装。
CDC是CObject的直接派生类,CDC类自己也有若干派生类,其中包括:
窗口客户区DC所对应的CClientDC类、OnPaint和OnDraw消息响应函数的输入参数中使用的CPaintDC类、图元文件对应的CMetaFileDC类和整个窗口所对应的CWindowDC类,参见图8-3。
在普通的MFC绘图中,一般直接使用CDC类即可。
CDC类中有许多成员函数,可以用来设置各种绘图环境、属性和参数,以及绘制各种图形和图像等,将在后面陆续加以介绍。
图8-3DC类
1.获得DC
在OnDraw函数中应该使用输入参数pDC,在其他函数中则可调用从CWnd类继承的成员函数GetDC来获得当前窗口(如客户区/视图类)DC的指针,该函数的原型为:
CDC*GetDC();
注意,每次从OnDraw函数的输入参数或调用GetDC所获得的DC,都是一个全新的临时默认DC,具有默认的绘图环境和设置。
它不能用类变量来长期保存,而且原来选入的各种GDI对象全都被作废、原来设置的各种状态也失效,一切都必须从头再来。
2.释放DC
因为Windows限制可用DC的数量,所以DC属于稀缺的公用资源。
因此,对每次获得的DC,在使用完成后必须立即释放。
从OnDraw函数的输入参数pDC获得的DC,在该函数运行结束后,系统会自动释放。
但由GetDC所获得的DC,则必须自己来手工释放,这可以通过调用从CWnd类继承的成员函数ReleaseDC来完成。
该函数的原型为:
intReleaseDC(CDC*pDC);//成功返回非0
例如:
voidCDrawView:
:
OnLButtonUp(UINTnFlags,CPointpoint)
{
CDC*pDC=GetDC();//获取DC
pDC->SelectObject(&pen);//选入笔
pDC->Rectangle(&rect);//绘制矩形
ReleaseDC(pDC);//释放DC
CView:
:
OnLButtonUp(nFlags,point);
}
3.安全DC句柄
可以用CDC类的成员函数GetSafeHdc来获取DC所对应窗口(如客户区)的安全DC句柄,该函数的原型为:
HDCGetSafeHdc();
与用GetDC函数所得到的临时DC不同,该安全DC句柄在窗口的存在期间内一直是有效的。
例如,可先定义类变量HDCm_hDC;,再在适当的地方给它赋值m_hDC=GetDC()->GetSafeHdc();,然后就可以放心地使用了。
还可以使用CDC类的成员函数Attach来将一空CDC对象与此安全DC句柄连接在一起,该函数的原型为:
BOOLAttach(HDChDC);//成功返回非0
4.屏幕DC
可以以NULL为输入参数,调用全局的API函数GetDC:
HDCGetDC(HWNDhWnd);
来可获取屏幕DC的句柄。
例如:
HDChdc=:
:
GetDC(NULL);//获取屏幕DC的句柄
Ellipse(hdc,0,0,150,100);//用API函数在屏幕左上角画一椭圆
也可以利用CDC类的成员函数Attach,将屏幕DC的句柄选入自定义的CDC类中,来构造屏幕CDC类的对象。
例如:
HDChdc=:
:
GetDC(NULL);//获取屏幕DC的句柄
CDCsDC;//定义屏幕DC(空)对象
sDC.Attach(hdc);//粘上屏幕DC句柄
sDC.Ellipse(0,0,150,100);//在屏幕左上角画一椭圆
8.3绘图颜色与工具
在WindowsAPI中用4个字节的双字来定义颜色类型COLORREF,有红(Red)绿(Green)蓝(Blue)三个字节分量,可用RGB宏来为颜色赋值。
在GDI中有画线状图的笔(pen)、画填充图的刷(brush)、画文字的字体(font)等绘图工具。
而GDI中使用的颜色种类则有4种之多,它们分别是像素所对应的点色、笔所对应的线色、刷所对应面色、文字所对应的文本色。
其中的像素和文本色,可以通过调用对应的专门函数来设置和获取。
而笔和刷的颜色,则必须先利用颜色参数创建笔和刷对象,然后调用通用的选择对象函数SelectObject将笔、刷等绘图工具选入DC,再利用DC来绘制各种颜色的图形。
8.3.1颜色
Windows中的颜色一般用4个字节表示(0BGR(整数序)或RGB0(字节序),因为IntelCPU的低位字节在前),Win32API中定义了一个专门表示颜色索引值的变量类型COLORREF(windef.h):
typedefDWORDCOLORREF;//0x00bbggrr
和一个由红绿蓝三原色构造颜色值的宏RGB(wingdi.h):
#defineRGB(r,g,b)
((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16)))
其中,r、g、b为字节变量,分部对应于红、绿、蓝三原色,取值范围为0~255。
RGB宏所对应的函数说明为:
COLORREFRGB(BYTEbRed,BYTEbGreen,BYTEbBlue);
例如:
COLORREFred,gray;
red=RGB(255,0,0);
gray=RGB(128,128,128);
在API中还定义了由COLORREF变量获取各个颜色分量的宏GetXValue(wingdi.h),它们对应的函数说明为(其中的DWORDrgb等价于COLORREFcol):
BYTEGetRValue(DWORDrgb);
BYTEGetGValue(DWORDrgb);
BYTEGetBValue(DWORDrgb);
8.3.2点色(像素)
在Windows中,像素(pixel)的颜色是直接由CDC类的成员函数SetPixel来设置的,该函数的原型为:
COLORREFSetPixel(intx,inty,COLORREFcrColor);
COLORREFSetPixel(POINTpoint,COLORREFcrColor);
其中,x与y分别为像素点的横坐标与纵坐标,crColor为像素的颜色值。
例如:
pDC->SetPixel(10,10,RGB(0,255,0));
另外,还可以用CDC的成员函数
COLORREFGetPixel(intx,inty)const;
COLORREFGetPixel(POINTpoint)const;
来获得指定点(x,y)或point的颜色。
例如:
COLORREFcol;
col=pDC->GetPixel(10,10);
8.3.3线色(笔)
在Windows中,线状图必须用笔(pen)来画,所以线的颜色就由笔色来确定。
在MFC中,笔的属性和功能由CPen类提供(CPen是CGDIObject的派生类)。
笔的创建与使用的步骤为:
1.创建笔对象
创建CPen类笔对象的方法有如下两种:
●使用非默认构造函数创建初始笔:
CPen(intnPenStyle,intnWidth,COLORREFcrColor);
其中:
⏹nPenStyle为笔的风格,可取值见表8-3。
表8-3笔风格nPenStyle值
符号常量
数值
风格名称
线例
PS_SOLID
0
实心
PS_DASH
1
虚线
PS_DOT
2
点线
PS_DASHDOT
3
虚点线
PS_DASHDOTDOT
4
虚点点线
PS_NULL
5
空笔
PS_INSIDEFRAME
6
框内
注意:
1~4号笔风格只是在笔宽=0或1时有效,笔宽>1时总为实心的。
⏹nWidth为笔宽,与映射模式有关,使用默认映射时为像素数,若nWidth=0,则不论什么映射模式,笔宽都为一个像素。
⏹crColor为笔的颜色值。
默认的笔为单像素宽的黑色实心笔。
例如:
CPen*pGrayPen=newCPen(PS_SOLID,0,RGB(128,128,128));
CPengrayPen(PS_SOLID,0,RGB(128,128,128));
●使用成员函数CreatePen(多次)创建笔:
BOOLCreatePen(intnPenStyle,intnWidth,COLORREFcrColor);
可先用CPen类的默认构造函数创建一个空笔对象,然后再调用CreatePen创建具有新内容的笔,例如:
CPengrayPen;
grayPen.CreatePen(PS_SOLID,0,RGB(128,128,128));
不过在用Creat