第8章绘图、字体和位图 81概述 82简单图形的绘制 83字体与文字处理 84位图、图标与光标
第8章 绘图、字体和位图 8.1 概述 8.2 简单图形的绘制 8.3 字体与文字处理 8.4 位图、图标与光标
81概述 81.1设备环境类 (1) CPaintDC CPaintDc类的构造函数会自动调用 BeginPaint,而它的析构函数则会自动调用 EndPaint (2) CClientDC FICWindowDC CWindowDO和 CClientDo构造函数分别调用 Get WindowDC和 GetO,但它们的析构函数 都是调用 ReleaseD函数。 (3) CMetaFileDC CMetaFileDC封装了在一个 Windows图元文件中绘图的方法。 81.1坐标映射 为了能保证打印的结果不受设备的影响, Windows定义了一些映射模式,这些映射模式决 定了设备坐标和逻辑坐标之间的关系。它们是: MM TEXT 每个逻辑单位等于一个设备像素,x向右为正,y向下为正 MM HIENGLISH 每个逻辑单位为0.001英寸,x向右为正,y向上为正 MM HIMETRIC 每个逻辑单位为001毫米,x向右为正,y向上为正 MM ANISOTROPIC x,y可变比例 MM ISOTROPIC x,y等比例 MM LOENGLISH 每个逻辑单位为001英寸,x向右为正,y向上为正 MM LOMETRIC 每个逻辑单位为0.1毫米,x向右为正,y向上为正 MM TWIPS 每个逻辑单位为一个点的1/20(一个点是1/72英寸), x向右为正,y向上为正
8.1 概述 8.1.1 设备环境类 (1) CPaintDC CPaintDC类的构造函数会自动调用BeginPaint,而它的析构函数则会自动调用EndPaint。 (2) CClientDC 和CWindowDC CWindowDC和CClientDC构造函数分别调用GetWindowDC和GetDC,但它们的析构函数 都是调用ReleaseDC函数。 (3) CMetaFileDC CMetaFileDC封装了在一个Windows图元文件中绘图的方法。 8.1.1 坐标映射 为了能保证打印的结果不受设备的影响,Windows定义了一些映射模式,这些映射模式决 定了设备坐标和逻辑坐标之间的关系。它们是: MM_TEXT 每个逻辑单位等于一个设备像素,x向右为正,y向下为正 MM_HIENGLISH 每个逻辑单位为0.001英寸,x向右为正,y向上为正 MM_HIMETRIC 每个逻辑单位为0.01毫米,x向右为正,y向上为正 MM_ANISOTROPIC x,y可变比例 MM_ISOTROPIC x,y等比例 MM_LOENGLISH 每个逻辑单位为0.01英寸,x向右为正,y向上为正 MM_LOMETRIC 每个逻辑单位为0.1毫米,x向右为正,y向上为正 MM_TWIPS 每个逻辑单位为一个点的1/20(一个点是1/72 英寸), x向右为正,y向上为正
81概述 在 MM ISOTROPIC映射模式下,纵横比总是1:1,换句话说,无论比例因子如何变化,圆总 是圆的;但在 MM ANISOTROPIO映射模式下,x和y的比例因子可以独立地变化,即圆可以 被拉扁成椭圆形状。 将一个椭圆绘制在视窗中央,且当视图的大小发生改变时,椭圆的形状也会随之改变: void CMy View: On Draw(CDC* pDC) CRect rectclient GetClientRect(rectClient) ∥获得当前窗口的客户区大小 DC-> SetMap Mode( MM ANISOTROPIC);∥设置 MM ANISOTROPIC映射模式 DC->Set WindowExt(1000, 1000) ∥设置窗口范围 DC-> Set ViewportExt( rectClient. right, -rectClient bottom)∥设置视口范围 pDC-> Set ViewportOrg(rectClient right/2, rectClient. bottom/2)∥设置视口原点 DC->Ellipse( CRect(-500,-500, 500, 500)) 813图形设备接口 1.使用GD对象 在选择GD对象进行绘图时,往往遵循着下列的步骤 (1)在堆栈中定义一个GD对象(如CPen、 CBrush对象),然后用相应的函数(如 CreatePen Create SolidBrush)创建此GDI对象
8.1 概述 在MM_ISOTROPIC映射模式下,纵横比总是1:1,换句话说,无论比例因子如何变化,圆总 是圆的;但在MM_ANISOTROPIC映射模式下,x和y的比例因子可以独立地变化,即圆可以 被拉扁成椭圆形状。 将一个椭圆绘制在视窗中央,且当视图的大小发生改变时,椭圆的形状也会随之改变: void CMyView::OnDraw(CDC* pDC) { CRect rectClient; GetClientRect(rectClient); // 获得当前窗口的客户区大小 pDC->SetMapMode(MM_ANISOTROPIC);// 设置MM_ANISOTROPIC映射模式 pDC->SetWindowExt(1000,1000); // 设置窗口范围 pDC->SetViewportExt(rectClient.right,-rectClient.bottom);// 设置视口范围 pDC->SetViewportOrg(rectClient.right/2,rectClient.bottom/2);// 设置视口原点 pDC->Ellipse(CRect(-500,-500,500,500)); } 8.1.3 图形设备接口 1. 使用GDI对象 在选择GDI对象进行绘图时,往往遵循着下列的步骤: (1) 在堆栈中定义一个GDI对象(如CPen、CBrush对象),然后用相应的函数(如CreatePen、 CreateSolidBrush)创建此GDI对象
81概述三 (2)将构造的GD对象选入当前设备环境中,但不要忘记将原来的GDI对象保存起来 (3)绘图结束后,恢复当前设备环境中原来的GDI对象。 (4)由于GD对象是在堆栈中创建中,当程序结束后,框架会自动删除程序创建的GD对象。 具体操作可像下面的代码过程 void CMy View: OnDraw( CDC* pDC) CPen penBlack ∥定义一个画笔变量 penBlack CreatePen( PS SOLID,2,RGB(0,0,0),∥创建画笔 ∥将此画笔选入当前设备环境并保存原来的画笔 CPen"pOldPen=pDC-SelectObject( &penBlack ∥用此画笔绘图 pDC->Move To() pDC->Line To(.) pDC->SelectObject( pOldPen ) ∥恢复设备环境中原来的画笔 库存的GD对象 Windows包含了一些库存的可以利用的GD对象。CDC的成员函数 Select StockObject可 以把一个库存对象选入当前设备环境中,并返回原先被选中的对象指针,同时使原先被选中 的对象从设备环境中分离出来。如下面的代码
8.1 概述 (2) 将构造的GDI对象选入当前设备环境中,但不要忘记将原来的GDI对象保存起来。 (3) 绘图结束后,恢复当前设备环境中原来的GDI对象。 (4) 由于GDI对象是在堆栈中创建中,当程序结束后,框架会自动删除程序创建的GDI对象。 具体操作可像下面的代码过程: void CMyView::OnDraw( CDC* pDC ) { CPen penBlack; // 定义一个画笔变量 penBlack.CreatePen( PS_SOLID, 2, RGB(0,0,0)); // 创建画笔 // 将此画笔选入当前设备环境并保存原来的画笔 CPen* pOldPen = pDC->SelectObject( &penBlack ); // 用此画笔绘图 pDC->MoveTo(...); pDC->LineTo(...); pDC->SelectObject( pOldPen ); // 恢复设备环境中原来的画笔 } 2. 库存的GDI对象 Windows包含了一些库存的可以利用的GDI对象。CDC的成员函数SelectStockObject可 以把一个库存对象选入当前设备环境中,并返回原先被选中的对象指针,同时使原先被选中 的对象从设备环境中分离出来。如下面的代码:
8.1概述 void CMy View: OnDraw( CDC* pDC CPen newPen( PS Solid, 2, rGb(0,0,0))) pDC->SelectObject( &newPen pDC-> MoveTo(…) pDC-> Lineto(…); pDC-> Select Object( BLACK PEN);∥ newMen被分离出来 函数 Selectstockobject可选用的库存GD对象类型可以是下列值之 BLACK BRUSH 黑色画刷 DKGRAY BRUSH 深灰色画刷 GRAY BRUSH 灰色画刷 HOLLOW BRUSH 中空画刷 LTGRAY BRUSH 浅灰色画刷 NULL BRUSH 空画刷 WHITE BRUSH 白色画刷 BLACK PEN 黑色画笔 NULL PEN 空画笔 WHITE PEN 白色画笔 DEVICE DEFAULT FONT设备默认字体 SYSTEM FONT 系统字体
8.1 概述 void CMyView::OnDraw( CDC* pDC ) { CPen newPen( PS_SOLID, 2, RGB(0,0,0) ) ) pDC->SelectObject( &newPen ); pDC->MoveTo(...); pDC->LineTo(...); pDC->SelectStockObject( BLACK_PEN ); // newPen被分离出来 } 函数SelectStockObject可选用的库存GDI对象类型可以是下列值之一: BLACK_BRUSH 黑色画刷 DKGRAY_BRUSH 深灰色画刷 GRAY_BRUSH 灰色画刷 HOLLOW_BRUSH 中空画刷 LTGRAY_BRUSH 浅灰色画刷 NULL_BRUSH 空画刷 WHITE_BRUSH 白色画刷 BLACK_PEN 黑色画笔 NULL_PEN 空画笔 WHITE_PEN 白色画笔 DEVICE_DEFAULT_FONT 设备默认字体 SYSTEM_FONT 系统字体
81概述 81.4颜色和颜色对话框 在MFC中,CDC使用的是RGB颜色空间。其中, COLORREF是用来表示RGB颜色的一个32位 的数据类型,它可以用下列的十六进制表示一个RGB值: 0xoobbggr 在具体操作RGB颜色时,还可使用下列的宏操作: GetB value 获得32位RGB颜色值中的蓝色分量 GetG Value 获得32位RGB颜色值中的绿色分量 GetRvalue 获得32位RGB颜色值中的红色分量 RGB 将指定的R、G、B分量值转换成一个32位的RGB颜色值 MFC的 C ColorDialog类为我们应用程序提供了颜色选择通用对话框,它具有下列的构造函数 CColorDialog( colorref clrInit=0, dWord dw Flags=0, CWnd= pParentW'nd= NULL ) 我们可以在 CColorDialog提供的颜色列表中选择一种颜色或定制一种颜色。当该对话框“OK” 退出(即 DoModal返回IOK)时,还可以调用下列成员获得相应的颜色 COLORREF GetColor()const ∥返回用户选择的颜色。 void SetCurrent color( COLORREF C),∥强制使用cr作为当前选择的颜色 statiC COlOrreF* GetSaved Custom Colors()/∥返回用户自己定义颜色 例如,下面的代码片断: CColorDialog dle if(dlg. DoModalo 1= IDOK)return; COLORREF my Color =dIg GeColorO
8.1 概述 8.1.4 颜色和颜色对话框 在MFC中,CDC使用的是RGB颜色空间。其中,COLORREF是用来表示RGB颜色的一个32位 的数据类型,它可以用下列的十六进制表示一个RGB值: 0x00bbggrr 在具体操作RGB颜色时,还可使用下列的宏操作: GetBValue 获得32位RGB颜色值中的蓝色分量 GetGValue 获得32位RGB颜色值中的绿色分量 GetRValue 获得32位RGB颜色值中的红色分量 RGB 将指定的R、G、B分量值转换成一个32位的RGB颜色值。 MFC的CColorDialog类为我们应用程序提供了颜色选择通用对话框,它具有下列的构造函数: CColorDialog( COLORREF clrInit = 0, DWORD dwFlags = 0, CWnd* pParentWnd = NULL ); 我们可以在CColorDialog提供的颜色列表中选择一种颜色或定制一种颜色。当该对话框“OK” 退出(即DoModal返回 IDOK)时,还可以调用下列成员获得相应的颜色。 COLORREF GetColor( ) const; // 返回用户选择的颜色。 void SetCurrentColor( COLORREF clr ); // 强制使用clr作为当前选择的颜色 static COLORREF * GetSavedCustomColors( );// 返回用户自己定义颜色 例如,下面的代码片断: CColorDialog dlg; if (dlg. DoModal() != IDOK) return; COLORREF myColor = dlg.GeColor();
81概述 815简单数据类CPon、CSie和 CRect 1. COin、 CSize和CRec类的构造函数 CPoint类带参数的常用构造函数原型如下 CPoint( int init, int initr); CPoint( Point initPt) CSize类带参数的常用构造函数原型如下: CSize( int initCX, int initCr) CSize( size initSize ) CRect类带参数的常用构造函数原型如下 CRect( int /, int t, int r, int b) CRect( const reCT& srcRect CRect( LPCReCt lp SrcRect ) CRect( point point, SIZE size ) CRect( POInT topLeft, PoinT bottom Right) 2. CPoint、CSie和 CRect的基本运算符操作 (1)“+”操作 若向 CPoint对象加上一个 CSize对象,则返回 CPoint对象。 若向 CRect对象加上一个 CPoint对象或 CSize对象,则返回CRec对象。 若向CRet对象加上一个 CSize对象,则将一个RECT(或 CRect)值偏移(移动) CSize大小
8.1 概述 8.1.5 简单数据类CPoint、CSize和CRect 1. CPoint、CSize和CRect类的构造函数 CPoint类带参数的常用构造函数原型如下: CPoint( int initX, int initY ); CPoint( POINT initPt ); CSize类带参数的常用构造函数原型如下: CSize( int initCX, int initCY ); CSize( SIZE initSize ); CRect类带参数的常用构造函数原型如下: CRect( int l, int t, int r, int b ); CRect( const RECT& srcRect ); CRect( LPCRECT lpSrcRect ); CRect( POINT point, SIZE size ); CRect( POINT topLeft, POINT bottomRight ); 2. CPoint、CSize和CRect的基本运算符操作 (1) “+”操作 若向CPoint对象加上一个CSize对象,则返回CPoint对象。 若向CRect对象加上一个CPoint对象或CSize对象,则返回CRect对象。 若向CRect对象加上一个CSize对象,则将一个RECT(或CRect)值偏移(移动)CSize大小
81概述 (2)“3操作 若从 COin对象减去一个 CSize对象,则返回一个 CPoint对象。 若从 COin对象减去一个 CPoint对象,则返回一个 CSize对象。 若从 CRect对象减去一个 CPoint对象或 CSize对象,则返回一个 CRect对象。 3. CRect类的常用操作 由于一个CRec类对象包含用于定义矩形的左上角和右下角点的成员变量,因此在传递 LPRECT、 LPCRECT或RECT结构作为参数的任何地方,都可以使用 CRect对象来代替。 成员函数 InflateRect和 DeflateRect用来扩大和缩小一个矩形。由于它们的操作是相互的, 也就是说,若指定 InflateRect函数的参数为负值,那么操作的结果是缩小矩形,因此下面只给 出 InflateRect函数的原型: void InflateRect( int x, int y) void InflateRect( sIzE Size void InflateRect( LPCreCt lpRect void InflateRect( int 1, int t, int r, int b) 成员函数 Intersectrect和 Unionrect分别用来将两个矩形进行相交和合并,当结果为空时 返回 FALSE,否则返回TRUE。它们的原型如下 BOOL IntersectRect( LPCRECt lpRect1, LPCRECT lpRect2) BOOL UnionRect( LPCRect lpRect/, LPCrect lpRect2
8.1 概述 (2) “-”操作 若从CPoint对象减去一个CSize对象,则返回一个CPoint对象。 若从CPoint对象减去一个CPoint对象,则返回一个CSize对象。 若从CRect对象减去一个CPoint对象或CSize对象,则返回一个CRect对象。 3. CRect类的常用操作 由于一个CRect类对象包含用于定义矩形的左上角和右下角点的成员变量,因此在传递 LPRECT、LPCRECT或RECT结构作为参数的任何地方,都可以使用CRect对象来代替。 成员函数InflateRect和DeflateRect用来扩大和缩小一个矩形。由于它们的操作是相互的, 也就是说,若指定InflateRect函数的参数为负值,那么操作的结果是缩小矩形,因此下面只给 出InflateRect函数的原型: void InflateRect( int x, int y ); void InflateRect( SIZE size ); void InflateRect( LPCRECT lpRect ); void InflateRect( int l, int t, int r, int b ); 成员函数IntersectRect和UnionRect分别用来将两个矩形进行相交和合并,当结果为空时 返回FALSE,否则返回TRUE。它们的原型如下: BOOL IntersectRect( LPCRECT lpRect1, LPCRECT lpRect2 ); BOOL UnionRect( LPCRECT lpRect1, LPCRECT lpRect2 );
8.1概述 其中, prEeti和 lpRect2用来指定操作的两个矩形。例如: CRect ectoNe(125, 0, 150, 200) CRect rect Two( 0, 75, 350, 95) CRect rectInter rectInter. IntersectRect(rectOne, rect Two) ∥结果为(125,75,150,95) asserT(rectInter = CRect(125, 75, 150, 95)) rectInter. UnionRect (rectOne, rect Two) ∥结果为(0,0,350,200) AssERT(rectInter == CRect(0, 0, 350, 200))
8.1 概述 其中,lpRect1和lpRect2用来指定操作的两个矩形。例如: CRect rectOne(125, 0, 150, 200); CRect rectTwo( 0, 75, 350, 95); CRect rectInter; rectInter.IntersectRect(rectOne, rectTwo); // 结果为(125, 75, 150, 95) ASSERT(rectInter == CRect(125, 75, 150, 95)); rectInter.UnionRect (rectOne, rectTwo); // 结果为(0, 0, 350, 200) ASSERT(rectInter == CRect(0, 0, 350, 200));
8.2简单图形的绘制 821创建画笔 创建一个修饰画笔,可以使用CPen类的 CreatePen函数,其原型如下 BOOL CreatePen( int nPenStyle, int nWidth, COlORREF crColor 其中,参数 nPenStyle、 n width、 crColor分别用来指定画笔的风格、宽度和颜色。 BOOL CreatePenIndirect( LPlogPen lpLogPen 此函数用由 LOGPEN结构指针指定的相关参数创建画笔, LOGPEN结构如下 typedef struct tag LOGPEN i *lgp*/ UINT lopn Style,∥画笔风格,同上 POINT loan Width;/PONT结构的y不起作用而用x表示画笔宽度 COLORREF lopn color ∥画笔颜色 1 LOGPEN 值得注意的是: 当修饰画笔的宽度大于1个像素时,画笔的风格只能取 PS NULL、 PS SOLID或 PS INSIDEFRAME,定义为其他风格不会起作用。 画笔的创建工作也可在画笔的构造函数中进行,它具有下列原型 CPen( int nPen Style, int nWidth, colOrreF crColor
8.2 简单图形的绘制 8.2.1 创建画笔 创建一个修饰画笔,可以使用CPen类的CreatePen函数,其原型如下: BOOL CreatePen( int nPenStyle, int nWidth, COLORREF crColor ); 其中,参数nPenStyle、nWidth、crColor分别用来指定画笔的风格、宽度和颜色。 BOOL CreatePenIndirect( LPLOGPEN lpLogPen ); 此函数用由LOGPEN结构指针指定的相关参数创建画笔,LOGPEN结构如下: typedef struct tagLOGPEN { /* lgpn */ UINT lopnStyle; // 画笔风格,同上 POINT lopnWidth;// POINT结构的y不起作用,而用x表示画笔宽度 COLORREF lopnColor; // 画笔颜色 } LOGPEN; 值得注意的是: n 当修饰画笔的 宽度大于1 个像素时,画 笔的风格只能 取PS_NULL、PS_SOLID 或 PS_INSIDEFRAME,定义为其他风格不会起作用。 n 画笔的创建工作也可在画笔的构造函数中进行,它具有下列原型: CPen( int nPenStyle, int nWidth, COLORREF crColor );