MFC绘图.docx
《MFC绘图.docx》由会员分享,可在线阅读,更多相关《MFC绘图.docx(36页珍藏版)》请在冰点文库上搜索。
MFC绘图
MFC编程之三:
绘图-1(画图)
绘图一般在视图类的(屏幕/打印机)绘图消息响应函数OnDraw中进行,例如:
voidCTestView:
:
OnDraw(CDC*/*pDC*/){
CTestDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
if(!
pDoc)
return;
//TODO:
在此处为本机数据添加绘制代码
}
每次需要重绘窗口时(程序启动/窗口大小改变/全部或部分窗口重现/程序员调用RedrawWindow或UpdateWindow),应用程序框架都会调用该CWnd的消息响应成员函数(的覆盖)来绘制窗口客户区。
在Windows中,绘图一般在视图窗口的客户区进行,使用的是MFC的设备上下文(DC=Device-Context)类CDC中各种绘图函数。
在绘图前,必须先得到客户区大小和DC、设置绘图颜色,然后再根据文档数据或用户操作来绘制图形。
1几何对象的结构和类
为了使用绘图函数,应该先了解绘图所用到的几种表示几何对象的结构和类。
这些结构和类分别定义在头文件windef.h和afxwin.h中。
1.点
1)点结构POINT
点数据结构POINT用来表示一点的x、y坐标:
typedefstructtagPOINT{
LONGx;
LONGy;
}POINT;
2)点类CPoint
点类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对象之间的运算。
2.大小
1)大小结构SIZE
大小(size尺寸)结构SIZE用来表示矩形的宽cx和高cy:
typedefstructtagSIZE{
LONGcx;
LONGcy;
}SIZE;
2)大小类CSize
大小类CSize也为一个没有基类的独立类,封装了SIZE结构,有成员变量cx和cy,其构造函数也有5种:
CSize();
CSize(intinitCX,intinitCY);
CSize(SIZEinitSize);
CSize(POINTinitPt);
CSize(DWORDdwSize);//低字设为cx、高字设为cy
CSizet类也重载了+、-、+=、-=、==、!
=等运算符来支持CSize对象和CSize、POINT、SIZE、RECT对象之间的运算。
3.矩形
1)矩形结构RECT
矩形结构RECT定义了矩形的左上角与右下角的坐标:
typedefstructtagRECT{
LONGleft;
LONGtop;
LONGright;
LONGbottom;
}RECT;
2)矩形类CRect
矩形类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;
BOOL PtInRect(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:
Addyourmessagehandlercodehereand/orcalldefault
if(rect.PtInRect(point)){
......
}
......
CView:
:
OnLButtonUp(nFlags,point);
}
2客户区大小和DC
在绘图前,必须先得到客户区大小和设备上下文DC。
1.获得客户区
绘图一般都是在视图窗口的客户区进行,而客户区的大小在运行时可由用户改变,为了使绘制的图形能随窗口大小自动改变,必须先得到当前客户区大小的数据(宽w和高h)。
获取客户区大小的方法有如下两种:
1)在消息响应函数OnSize中获得
利用属性窗口的信息页,在视图类中添加WM_SIZE消息的响应函数OnSize。
该函数在窗口第一次显示或窗口大小被改变时会被Windows系统调用。
其输入参数中的cx和cy就是客户区大小的宽和高,可将它们赋值给类变量(如m_iW和m_iH)供绘图时使用。
例如
voidCDrawView:
:
OnSize(UINTnType,intcx,intcy){
CView:
:
OnSize(nType,cx,cy);
//TODO:
在此处添加消息处理程序代码
m_iW=cx; m_iH=cy;
}
其中,nType的值为:
l SIZE_MAXIMIZED(窗口已被最大化)
l SIZE_MINIMIZED(窗口已被最小化)
l SIZE_RESTORED(窗口已被改变大小)
l SIZE_MAXHIDE(其他窗口被最大化)
l SIZE_MAXSHOW(其他窗口从最大化还原)
2)调用成员函数GetClientRect得到
可在绘图前,定义一个矩形变量rect,然后再调用CWnd类的成员函数GetClientRect:
voidGetClientRect(LPRECTlpRect)const;
得到当前客户区矩形的数据,其中的右(right)与底(bottom)就是客户区的宽与高(其左left与顶top都为0)。
例如:
RECTrect;
GetClientRect(&rect);
intw=rect.right,h=rect.bottom;
2.DC
在Windows中,绘图使用的是MFC的DC(Device-Context, 设备上下文)类CDC中各种绘图函数。
0)CDC类
CDC是CObject的直接派生类,CDC类自己也有若干派生类,其中包括窗口客户区DC所对应的CClientDC类、OnPaint和OnDraw消息响应函数的输入参数中使用的CPaintDC类、图元文件对应的CMetaFileDC类和整个窗口所对应的CWindowDC类。
CDC类中有许多成员函数,可以用来设置各种绘图环境、属性和参数,以及绘制各种图形和图像等,将在后面陆续加以介绍。
1)获得DC
可以从OnDraw函数的输入参数pDC或调用CWnd的成员函数GetDC:
CDC*GetDC();
来获得DC的指针。
2)释放DC
因为Windows限制可用DC的数量,所以DC属于稀缺的公用资源。
因此,对每次获得的DC,在使用完成后必须立即释放。
从OnDraw函数的输入参数pDC获得的DC,在该函数运行结束后,系统会自动释放。
但由GetDC所获得的DC,必须自己来释放,这可以通过调用CWnd的成员函数ReleaseDC来完成:
intReleaseDC(CDC*pDC);// 成功返回非0
例如:
voidCDrawView:
:
OnLButtonUp(UINTnFlags,CPointpoint)
{
ReleaseCapture();
if(m_bLButtonDown){
CDC*pDC= GetDC();
pDC->SelectObject(newCPen(PS_SOLID,0,RGB(255,0,0)));
pDC->SelectStockObject(NULL_BRUSH);
pDC->Ellipse(rect);
ReleaseDC(pDC);
m_bLButtonDown=FALSE;
}
CView:
:
OnLButtonUp(nFlags,point);
}
3)类DC
每次从OnDraw函数的输入参数或调用GetDC所获得的DC,都是一个全新的临时缺省DC。
它不能用类变量来长期保存,而且原来选入的各种GDI对象全都被作废,必须从头再来。
为了使选入的各种GDI对象一直有效,必须在视图类的PreCreateWindow函数中调用CWnd类的成员函数AfxRegisterWndClass:
LPCTSTRAFXAPIAfxRegisterWndClass(UINTnClassStyle,HCURSORhCursor=0,
HBRUSHhbrBackground=0,HICONhIcon=0);
来修改窗口类的风格属性中的DC为类DC:
CS_CLASSDC。
如
BOOLCDrawView:
:
PreCreateWindow(CREATESTRUCT&cs){
cs.lpszClass= AfxRegisterWndClass(CS_DBLCLKS|CS_HREDRAW|
CS_VREDRAW| CS_CLASSDC,0,
:
:
CreateSolidBrush(RGB(255,255,255)));
returnCView:
:
PreCreateWindow(cs);
}
4)安全DC句柄
也可以用CDC类的成员函数:
HDCGetSafeHdc();
来获取CD所对应窗口(如客户区)的安全DC句柄,该句柄在窗口存在期间一直是有效的。
例如,可先定义类变量HDCm_hDC;,再在适当的地方给它赋值m_hDC=GetDC()->GetSafeHdc();,然后就可以放心地使用了。
例如,可以使用CDC类的成员函数
BOOLAttach(HDChDC);// 成功返回非0
来将CDC对象与DC句柄连接在一起。
3设置绘图颜色
1.颜色
Windows中的颜色一般用4个字节表示(0BGR(整数)=RGB0(字节序)[IntelCPU低位字节在前]),Win32API中定义了一个专门表示颜色索引值的变量类型COLORREF:
(windef.h)
typedefDWORD COLORREF;//0x00bbggrr
和一个由红绿蓝三原色构造颜色值的宏RGB:
(wingdi.h)
#define RGB(r,g,b)((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16)))
其中,r、g、b为字节变量,取值范围为0~255。
其函数说明为:
COLORREF RGB(
BYTEbRed, //redcomponentofcolor
BYTEbGreen, //greencomponentofcolor
BYTEbBlue //bluecomponentofcolor
);
例如:
COLORREFred,gray;
red=RGB(255,0,0);
gray=RGB(128,128,128);
在API中还定义了由COLORREF变量获取各个颜色分量的宏Get?
Value:
(wingdi.h)
#defineGetRValue(rgb) (LOBYTE(rgb))
#defineGetGValue(rgb) (LOBYTE(((WORD)(rgb))>>8))
#defineGetBValue(rgb) (LOBYTE((rgb)>>16))
其中:
typedefunsignedlongULONG_PTR;
typedefULONG_PTRDWORD_PTR;
#defineLOBYTE(w) ((BYTE)((DWORD_PTR)(w)&0xff))
它们对应的函数说明为:
BYTEGetRValue(DWORDrgb); //DWORDrgb~COLORREFcol
BYTEGetGValue(DWORDrgb);
BYTEGetBValue(DWORDrgb);
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);
3.线色(笔)
在Windows中,线状图必须用笔(pen)来画,所以线的颜色就由笔色来确定。
在MFC中,笔的属性和功能由CPen类提供(CPen是CGDIObject的派生类)。
笔的创建与使用的步骤为:
1)创建笔对象:
创建笔类CPen对象的方法有如下两种:
使用构造函数CPen:
CPen(intnPenStyle,intnWidth,COLORREFcrColor);
其中:
nPenStyle为笔的风格,可取值:
PS_SOLID,PS_DASH,PS_DOT,PS_DASHDOT,PSDASHDOTDOT
注意:
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);
如:
CPengrayPen;
grayPen.CreatePen(PS_SOLID,0,RGB(128,128,128));
缺省的笔为单像素宽的实心黑色笔
2)将笔对象选入设备上下文:
为了能使用我们所创建的笔对象,必须先将它选入设备上下文,这可以调用设备上下文类CDC的成员函数SelectObject来完成:
CPen*SelectObject(CPen*pPen);
返回值为指向原来笔对象的指针(一般将其保存下来,供下次再装入时使用)。
如
pOldPen=pDC->SelectObject(&pen);
另外,Windows中有一些预定义的笔对象,可用CDC的另一成员函数SelectStockObject将其选入DC,其函数原型为:
virtualCGdiObject*SelectStockObject(intnIndex);
预定义的笔对象有BLACK_PEN(黑色笔)、WHITE_PEN(白色笔)、NULL_PEN(空笔/无色笔)。
例如:
pDC->SelectStockObject(BLACK_PEN);
3)使用设备上下文画线状图:
画线状图以及面状图的边线,所使用的是当前设备上下文中的笔对象。
线状图有直线、折线、矩形、(椭)圆(弧)等,详见4)
(2)
4)将笔对象从设备上下文中放出:
为了能删除使用过的笔对象,必须先将它从设备上下文中释放出来后,然后才能删除。
释放的方法是装入其他的笔对象(一般是重新装入原来的笔对象)。
例如
pDC->SelectObject(pOldPen);
5) 删除笔对象:
为了能删除笔对象,必须先将其从设备上下文中释放。
删除方法有如下几种:
调用笔类CDC的成员函数DeleteObject删除笔的当前内容(但是未删除笔对象,以后可再用成员函数CreatePen在笔对象中继续创建新的笔内容)。
如
pen.DeleteObject();
使用删除运算符delete将笔对象彻底删除,如deletepen;
自动删除:
若笔对象为局部变量,则在离开其作用域时,会被系统自动删除
下面为一段较完整地创建与使用笔的例子代码:
CPenpen,*pOldPen;
for(intj=0;j<=255;j++){
HSLtoRGB(m_hue,m_sat,255-j,r,g,b);// 自定义的函数
pen.CreatePen(PS_SOLID,0,RGB(r,g,b));
pOldPen=pDC->SelectObject(&pen);
pDC->MoveTo(0,j);pDC->LineTo(40,j);
pDC->SelectObject(pOldPen);
pen.DeleteObject();
}
4.面色(刷)
在Windows中,面状图必须用刷(brush)来填充,所以面色是由刷色来确定的。
MFC中的刷类为CBrush(它也是CGDIObject的派生类),刷的创建与使用的步骤与笔的相似。
1)构造函数有4个:
CBrush();//创建一个刷的空对象
CBrush(COLORREFcrColor);//创建颜色为crColor的实心刷
CBrush(intnIndex,COLORREFcrColor);// 创建风格由nIndex指定且颜色为crColor的条纹(hatch孵化)刷,其中nIndex可取条纹风格(HatchStyles)值:
符号常量
数字常量
风格
HS_HORIZONTAL
0
水平线
HS_VERTICAL
1
垂直线
HS_FDIAGONAL
2
正斜线
HS_BDIAGONAL
3
反斜线
HS_CROSS
4
十字线(正网格)
HS_DIAGCROSS
5
斜十字线(斜网格)
CBrush(CBitmap*pBitmap);//创建位图为pBitmap的图案刷
如:
pDC->FillRect(&rect,newCBrush(RGB(r,g,b)));
与构造函数相对应,有多个创建不同类型刷的成员函数:
BOOLCreateSolidBrush(COLORREFcrColor);
BOOLCreateHatchBrush(intnIndex,COLORREFcrColor);
BOOLCreatePatternBrush(CBitmap*pBitmap);
BOOLCreateDIBPatternBrush(HGLOBALhPackedDIB,UINTnUsage);
BOOLCreateDIBPatternBrush(constvoid*lpPackedDIB,UINTnUsage);
BOOLCreateBrushIndirect(constLOGBRUSH*lpLogBrush);
BOOLCreateSysColorBrush(intnIndex);
预定义的刷对象有BLACK_BRUSH(黑刷)、DKGRAY_BRUSH(暗灰刷)、GRAY_BRUSH(灰刷)、HOLLOW_BRUSH(空