2、设置坐标映射
(1)Windows坐标系统
Windows坐标系分为逻辑坐标系和设备坐标系两种,GDI支持这两种坐标系。一般而言,
GDI的文本和图形输出函数使用逻辑坐标,而在客户区移动或按下鼠标的鼠标位置是采用设备坐标。
<1>逻辑坐标系是面向DC的坐标系,这种坐标不考虑具体的设备类型,在绘图时,Windows会根据当前设置的映射模式将逻辑坐标转换为设备坐标。
<2>设备坐标系是面向物理设备的坐标系,这种坐标以像素或设备所能表示的最小长度单位为单位,X轴方向向右,Y轴方向向下。设备坐标系的原点位置(0, 0)不限定在设备显示区域的左上角。
设备坐标系分为屏幕坐标系、窗口坐标系和客户区坐标系三种相互独立的坐标系。
l 屏幕坐标系以屏幕左上角为原点,一些与整个屏幕有关的函数均采用屏幕坐标,如GetCursorPos()、SetCursorPos()、CreateWindow()、MoveWindow()。弹出式菜单使用的也是屏幕坐标。
l 窗口坐标系以窗口左上角为坐标原点,它包括窗口标题栏、菜单栏和工具栏等范围。
l 客户区坐标系以窗口客户区左上角为原点,主要用于客户区的绘图输出和窗口消息的处理。鼠标消息的坐标参数使用客户区坐标,CDC类绘图成员函数使用与客户区坐标对应的逻辑坐标。
(2)坐标之间的相互转换
l 编程时,有时需要根据当前的具体情况进行三种设备坐标之间或与逻辑坐标的相互转换。
l MFC提供了两个函数CDC::DPtoLP()和CDC:: LPtoDP()用于设备坐标与逻辑坐标之间的相互转换。
l MFC提供了两个函数CWnd::ScreenToClient()和CWnd::ClientToScreen()用于屏幕坐标与客户区坐标的相互转换。
(3)映射模式
l 映射模式确定了在绘制图形时所依据的坐标系,它定义了逻辑单位的实际大小、坐标增长方向,所有映射模式的坐标原点均在设备输出区域(如客户区或打印区)的左上角。此外,对于某些映射模式,用户还可以自定义窗口的长度和宽度,设置视图区的物理范围。
l Windows定义了8种映射模式,见下表。
l 映射模式使得程序员可不必考虑输出设备的具体设备坐标系,而在一个统一的逻辑坐标系中进行图形的绘制。
映射方法(Mapping Mode) | 逻辑单位 | 坐标轴方向 |
MM_TEXT(默认方式) | 1 pixel | X轴正方向朝右,Y轴正方向朝下 |
MM_LOMETRIC | 0.1 mm | X轴正方向朝右,Y轴正方向朝上 |
MM_HIMETRIC | 0.01 mm | X轴正方向朝右,Y轴正方向朝上 |
MM_LOENGLISH | 0.01 inch | X轴正方向朝右,Y轴正方向朝上 |
MM_HIENGLISH | 0.001 inch | X轴正方向朝右,Y轴正方向朝上 |
MM_TWIPS | 1/1440 inch | X轴正方向朝右,Y轴正方向朝上 |
MM_ISOTROPIC | 自定义(X=Y) | 自定义 |
MM_ANISOTROPIC | 自定义(X!=Y) | 自定义 |
当绘制的图形需要随着窗口的大小改变而自动改变的时候,一般选择MM_ISOTROPIC和MM_ANISOTROPIC映射方式。它们的唯一区别就是前者的X轴和Y轴的逻辑单位的大小是相同的,单词“isotropic”就是各个方向相等的意思,此映射方式适合绘制圆或正方形。而实际应用中,常常给X轴和Y轴取不同的比例,这时候选择MM_ANISOTROPIC映射方式。单词“anisotropic”就是各个方向相异的意思。
(4)自定义映射模式
“窗口”和“视口”的概念:
窗口(Window):对应逻辑坐标系上程序员设定的区域
视口(Viewport):对应实际输出设备上程序员设定的区域
l 窗口原点是指逻辑窗口坐标系的原点在视口(设备)坐标系中的位置,视口原点是指设备实际输出区域的原点。
l 除了映射模式,窗口和视口也是决定一个点的逻辑坐标如何转换为设备坐标的一个因素。一个点的逻辑坐标按照如下式子转换为设备坐标:
设备(视口)坐标 = 逻辑坐标 – 窗口原点坐标 + 视口原点坐标
//定义坐标映射方式
WINGDIAPI int WINAPI SetMapMode(HDC, int);
此API函数在MFC中封装为CDC::virtual int SetMapMode(int nMapMode);
//定义逻辑窗口区域,单位为逻辑单位(Logical)
WINGDIAPI BOOL WINAPI SetWindowExtEx (HDC, int, int, LPSIZE);
此API函数在MFC中封装为CDC::virtual CSize SetWindowExt(int cx, int cy);
//设置逻辑窗口的原点坐标,缺省原点为(0,0)。
WINGDIAPI BOOL WINAPI SetWindowOrgEx(HDC, int, int, LPPOINT);
此API函数在MFC中封装为CDC::CPoint SetWindowOrg(int x, int y);
注意:SetWindowOrg(Ex) 只有在映射模式为MM_ANISOTROPIC或MM_ISOTROPIC时才有意义。
//定义视口的坐标轴方向及区域、定义域和值域,单位为像素(Pixel)
WINGDIAPI BOOL WINAPI SetViewportExtEx(HDC, int, int, LPSIZE);
此API函数在MFC中封装为CDC::virtual CSize SetViewportExt(int cx, int cy);
注意:SetViewportExt(Ex) 只有在映射模式为MM_ANISOTROPIC或MM_ISOTROPIC时才有意义。
//设置视口的原点坐标,缺省原点为(0,0)。
WINGDIAPI BOOL WINAPI SetViewportOrgEx(HDC, int, int, LPPOINT);
此API函数在MFC中封装为CDC:: virtual CPoint SetViewportOrg(int x, int y);
参考:《GDI中的坐标映射问题》http://dev.csdn.net/article/12/12013.shtm
3、创建绘图工具并选入DC
有了画布,要绘图我们必须有画笔画刷。在Windows中有HPEN、HBRUSH等GDI对象,MFC对GDI对象进行了很好的封装,提供了封装GDI对象的类,如CPen、CBrush、CFont、CBitmap和CPalette等,这些类都是GDI对象类CGdiObject的派生类。
一般先创建画笔(刷),然后调用CDC::SelectObject函数将画笔(刷)选入设备环境最为当前绘图工具,绘图完毕恢复设备环境以前的画笔(刷)对象,最后调用CGdiObject::DeleteObject函数删除画笔(刷)对象。
这里需要注意的是,CGdiObject::DeleteObject函数彻底删除底层GDI对象(CPen和CBrush类的基类)。在MFC中,当对象销毁时会调用对象的析构函数自动删除对象,一般不必调用CGdiObject::DeleteObject删除GDI对象,因为如果设备环境还在使用一个GDI对象时,将引起应用程序崩溃或出现难以理解的运行错误。
(1)创建画笔
BOOL CPen::CreatePen( int nPenStyle, int nWidth, COLORREF cfColor );
nPenStyle 指定画笔的风格。其可能取值的列表,请参见CPen构造函数中的nPenStyle参数。
nWidth 指定画笔的宽度。如果这个值为0,则不管是什么映射模式,以设备单位表示的宽度总是一个像素。
crColor 包含画笔的一个RGB颜色,为COLORREF结构。
此外,可通过CDC::SelectStockObject函数来调用系统预定义的库存笔对应的CGdiObject对象。
pOldPen = (Cpen*)pDC->SelectStockObject(BLACK_PEN);
(2)创建画刷
BOOL CBrush::CreateSolidBrush ( COLORREF crColor );
BOOL CBrush::CreateHatchBrush( int nIndex, COLORREF crColor );
参数: nIndex 指定画刷的阴影线风格。可取的值如下:
HS_HORIZONTAL /* ==== */
HS_VERTICAL /* ||||| */
HS_FDIAGONAL /* / */
HS_BDIAGONAL /* / */
HS_CROSS /* +++++ */
HS_DIAGCROSS /* xxxxx */
返回值:调用成功时返回非零值,否则为0。
此外,可通过CDC::SelectStockObject函数来调用系统预定义的库存画刷对应的CGdiObject对象。
pOldBrush = (CBrush*)pDC->SelectStockObject(BLACK_BRUSH);
(3)将画笔(刷)选入设备环境。
以下为MFC中默认映射方式下的GDI绘图的模块:
//先获取设备环境pDC
CPen *pOldPen,newPen;
CBrush *pOldBrush,newBrush1,newBrush2;
//创建宽度为pixel的白色实线画笔
newPen.CreatePen(PS_SOLID,1,RGB(0,0,0));
//创建红色实线画刷
newBrush1.CreateSolidBrush(RGB(255,0,0));
//创建红色实线度的向下(从右到左)影线的阴影画刷
newBrush2.CreateHatchBrush(HS_BDIAGONAL,RGB(255,0,0));
//将newPen画笔和newBrush1画刷对象选入设备环境
pOldPen = pDC->SelectObject(&newPen);
pOldBrush = pDC->SelectObject(&newBrush1);
//调用DC绘图函数绘图
//……
//绘图完毕,恢复原来画笔、画刷
pDC->SelectObject(pOldPen);
pDC->SelectObject(pOldBrush);
//删除创建的画笔、画刷
// newPen.DeleteObject();
// newBrush1.DeleteObject();
// newBrush2.DeleteObject();
(4)当绘制文本Text时,一般可以通过调用CDC::SetBkColor函数来设置背景颜色,调用CDC::SetTextColor函数来设置文字颜色,调用CDC::SetTextAlign函数设置文本对齐标记。
4、调用DC绘图函数绘图
GDI为提供了绘制基本图形的成员函数,在MFC中这些函数封装在CDC类中。
注意:绘图函数使用的坐标都是逻辑坐标。
常用CDC绘图函数 | |
函数 | 功能 |
线输出函数 | |
GetCurrentPosition | 获取笔的当前位置(以逻辑坐标表示) |
MoveTo | 移动当前位置 |
LineTo | 从当前位置到一点画直线,但不包括那个点 |
Arc | 画一段椭圆弧 |
ArcTo | 画一段椭圆弧。除了更新当前位置以外,这个函数与Arc类似 |
PolyPolyline | 画多组相连线段。这个函数不使用也不更新当前位置 |
PolylineTo | 画一条或多条直线,并把当前位置移到最后一条直线的终点 |
PolyBezier | 画一条或多条Bezier样条。不使用也不更新当前位置 |
PolyBezierTo | 画一条或多条Bezier样条,并把当前位置移到最后一条Bezier样条的终点 |
|
|
椭圆和多边形函数 | |
Chord | 绘制椭圆弧(椭圆和一条线段相交围成的闭合图形) |
DrawFocusRect | 绘制用于表示焦点的风格的矩形 |
Ellipse | 绘制椭圆 |
Pie | 绘制饼形图 |
Polygon | 绘制多边形,包含由线段连接的一个或多个点(顶点) |
PolyPolygon | 创建使用当前多边形填充模式的两个或多个多边形,多边形可以相互分开或叠加 |
Polyline | 绘制多边形,包含连接指定点的一组线段 |
Rectangle | 使用当前笔绘制矩形,用当前画刷填充 |
RoundRect | 使用当前笔绘制圆角矩形,用当前画刷填充 |
位图函数 | |
BitBlt | 从指定设备上下文拷贝位图 |
StretchBlt | 把位图由源矩形和设备移动到目标矩形,必要时拉伸或压缩位图以适合目标矩形的维数 |
GetPixel | 获取指定点像素的RGB颜色值 |
SetPixel | 设置指定点像素为最接近指定色的近似值 |
文本函数 | |
TextOut | 用当前选取字体在指定位置写字符串 |
ExtTextOut | 用当前选取字体在矩形区域写字符串 |
TabbedTextOut | 在指定位置写字符串,制表符扩展为制表符停止位置数组中指定值 |
DrawText | 在指定矩形内绘制格式化文本 |
-------------------详情参考MSDN、MFC类库详解----------------- |
--------------------To be continued------------------