第10单元图形设备接口 第10单元图形设备接口 本单元教学目标 介绍 Windows的图形设备接口(GD1)和MFC的图形对象 学习要求 了解图形设备接口的概念,掌握画笔、画刷和字体的用法,以及逻辑坐标和设备坐标的 概念 授课内容 在 Windows程序中,应用程序的输出并不直接面向物理的设备,如显示屏或打印机, 而是针对一个称之为设备环境( Device Context)的逻辑设备进行操作,设备环境与实际设 备之间的信息传送由 Windows直接管理 在MFC应用程序中,所有的绘制调用均通过相应的设备环境对象实现,设备环境对象 封装了相应的 Windows apl功能,由一个32位的HDC类型句柄标识。在MFC类库中,用 CDC类封装设备文本对象。 CPaintDc类是从CDC类派生的设备环境类。 CPaintDC类的对象在 OnPaint()函数中 使用。另外, CClientDo类也是常用的CDC派生类,用于在 OnPaint()函数外访问设备环 境 在第9单元的程序举例中,我们已经看到了 CPaintDC类的应用。但是,那些举例都很 单调,没有颜色、线型和字体的变化。本单元首先介绍一些在设备环境下使用的绘图工具(图 形设备接口对象),使用它们可改善应用程序的外观,然后介绍图形设备接口(GD1)的坐 标系统 10.1画笔与画刷 画笔是用来画线的工具,是CPen类的对象。其使用方法为 /声明画笔对象,并创建宽度为3的红色实线画笔 CPen penNed nRed. CreatePen (PS solid, 3, RGB (255, 0, 0)) /使用新的画笔,保存原来的画笔以便恢复 CPen *pOldPen
第 10 单元 图形设备接口 - 195 - 第 10 单元 图形设备接口 本单元教学目标 介绍 Windows 的图形设备接口(GDI)和 MFC 的图形对象。 学习要求 了解图形设备接口的概念,掌握画笔、画刷和字体的用法,以及逻辑坐标和设备坐标的 概念。 授课内容 在 Windows 程序中,应用程序的输出并不直接面向物理的设备,如显示屏或打印机, 而是针对一个称之为设备环境(Device Context)的逻辑设备进行操作,设备环境与实际设 备之间的信息传送由 Windows 直接管理。 在 MFC 应用程序中,所有的绘制调用均通过相应的设备环境对象实现,设备环境对象 封装了相应的 Windows API 功能,由一个 32 位的 HDC 类型句柄标识。在 MFC 类库中,用 CDC 类封装设备文本对象。 CPaintDC 类是从 CDC 类派生的设备环境类。CPaintDC 类的对象在 OnPaint()函数中 使用。另外,CClientDC 类也是常用的 CDC 派生类,用于在 OnPaint()函数外访问设备环 境。 在第 9 单元的程序举例中,我们已经看到了 CPaintDC 类的应用。但是,那些举例都很 单调,没有颜色、线型和字体的变化。本单元首先介绍一些在设备环境下使用的绘图工具(图 形设备接口对象),使用它们可改善应用程序的外观,然后介绍图形设备接口(GDI)的坐 标系统。 10.1 画笔与画刷 画笔是用来画线的工具,是 CPen 类的对象。其使用方法为: // 声明画笔对象,并创建宽度为 3 的红色实线画笔 CPen penRed; penRed.CreatePen(PS_SOLID, 3, RGB(255, 0, 0)); // 使用新的画笔,保存原来的画笔以便恢复 CPen *pOldPen;
第10单元图形设备接口 196 pOldPen dc SelectObject(&pOldPen) //以下为作图代码,所画的线均使用新画笔 /恢复原来的画笔 dc. Select Object(pOldPen) 保存并恢复原来画笔的原因是,每个图形设备接口对象要占用一个HDC句柄,而可用的句 柄数量是有限的,在使用完后要及时释放。否则,每次执行 On Paint()函数时均要重新创 建图形接口对象,未被释放的非法句柄会留在设备上下文对象中,积累下去将导致严重的运 行错误 CPen类的成员函数 CreatePen()用于创建画笔,其原型为: BOOL CreatePen(int nPen Style, int n Width, COLORREF crColor); 第1个参数是画笔样式,可取 画笔样式 说明 IS SOLID 创建实线笔 PS DASH 创建由短线构成的虚线 PS DOT 创建由点构成的虚线 PS DASHDOT 创建由短线和点构成的虚线 PS DASH DOTDOT创建由短线、点、点构成的虚线 PS NULL 创建空(空白)画笔 各种虚线只有当线宽为1时有效。第2个参数为线宽,第3个参数为线的颜色,可使用RGB ()函数指定。RGB()函数有3个参数,分别代表选取颜色的红、绿、蓝分量,可取0 255之间的整数值。例如RGB(255,255,255)为白色,RGB(0,0,0)为黑色。 画刷是用来填充图形的工具,是 CBrush类的对象,使用方法与画笔类似,也要定义画 刷对象,创建画刷并保存原来的画刷,在绘图工作结束后恢复原来的画刷。创建画刷的成员 函数的原型为 BOOL Create Solid Brush( COLORREF crColor 参数 crColor指定了画刷的颜色。除此而外,还可以创建一个阴影风格的画刷: BOOL CreateHatch Brush( int nIndex, COLORREF crColor 其中参数 nIndex指定了阴影风格,可取值为: 阴影风格 说明 HS BDIAGONAL从左下角到右上角的45度斜线 HS CROSS 水平线与垂直线 HS DIAGCROSS 相互垂直的45度线 HS FDIAGONAL从左上角到右下角的45度斜线 HS HORIZONTAL水平线 HS VERTICAL 垂直线
第 10 单元 图形设备接口 - 196 - pOldPen = dc.SelectObject(&pOldPen); // 以下为作图代码,所画的线均使用新画笔 … … // 恢复原来的画笔 dc.SelectObject(pOldPen); 保存并恢复原来画笔的原因是,每个图形设备接口对象要占用一个 HDC 句柄,而可用的句 柄数量是有限的,在使用完后要及时释放。否则,每次执行 OnPaint()函数时均要重新创 建图形接口对象,未被释放的非法句柄会留在设备上下文对象中,积累下去将导致严重的运 行错误。 CPen 类的成员函数 CreatePen()用于创建画笔,其原型为: BOOL CreatePen (int nPenStyle, int nWidth, COLORREF crColor); 第 1 个参数是画笔样式,可取 画笔样式 说明 PS_SOLID 创建实线笔 PS_DASH 创建由短线构成的虚线 PS_DOT 创建由点构成的虚线 PS_DASHDOT 创建由短线和点构成的虚线 PS_DASH_DOTDOT 创建由短线、点、点构成的虚线 PS_NULL 创建空(空白)画笔 各种虚线只有当线宽为 1 时有效。第 2 个参数为线宽,第 3 个参数为线的颜色,可使用 RGB ()函数指定。RGB()函数有 3 个参数,分别代表选取颜色的红、绿、蓝分量,可取 0~ 255 之间的整数值。例如 RGB(255,255,255)为白色,RGB(0,0,0)为黑色。 画刷是用来填充图形的工具,是 CBrush 类的对象,使用方法与画笔类似,也要定义画 刷对象,创建画刷并保存原来的画刷,在绘图工作结束后恢复原来的画刷。创建画刷的成员 函数的原型为: BOOL CreateSolidBrush ( COLORREF crColor ); 参数 crColor 指定了画刷的颜色。除此而外,还可以创建一个阴影风格的画刷: BOOL CreateHatchBrush ( int nIndex, COLORREF crColor ); 其中参数 nIndex 指定了阴影风格,可取值为: 阴影风格 说明 HS_BDIAGONAL 从左下角到右上角的 45 度斜线 HS_CROSS 水平线与垂直线 HS_DIAGCROSS 相互垂直的 45 度线 HS_FDIAGONAL 从左上角到右下角的 45 度斜线 HS_HORIZONTAL 水平线 HS_VERTICAL 垂直线
第10单元图形设备接口 CDC类的 Selectobject()函数原型如下 CPen* SelectObject( CPen" pPen CBrush* SelectObject( CBrush* pBrush virtual CFont*SelectObject( CFont* pFont ) Selectobject()是重载的CDC类成员函数。 SelectObject()将一个GDl对象选入到设 备环境中,新选中的对象将替换原有的同类型对象,然后返回指向被替换的对象的指针 102绘画模式 在 Windows中,绘图的最终效果不但取决于画笔和画刷的设置,还可以通过设定绘图 模式来修正。屏幕绘图模式可通过CDC的成员函数 SetRoP2()设定,其原型为: int SetROP2( int nDrawMode 其中参数 n DrawMode为选定的绘图模式,常用模式有: 绘图模式 说明 R2 BLAC 无论画笔色如何,只用黑色绘图 WHITE 无论画笔色如何,只用白色绘图 R2 NOP 无论画笔色如何,用无色笔绘图 R2 NOT 用与背景色相反的颜色绘图 R2 NOTCOPYPEN用与画笔色相反的颜色绘图 R2 COPYPEN 用画笔色绘图 R2 XORPEN 对画笔色和背景色作异或(XOR)运算 其中R2NOT模式可保证所绘图形是可见的,即如果画笔色与背景色相同,则以与背景色 相反的颜色作图,避免了所画图形“淹没”在背景中;R2ⅹ ORPEN模式有一种特殊效果, 即对同一条线画两次会起到擦除作用 函数的返回值为原来的绘图模式 10.3GDI坐标系 GD支持两种类型的坐标系,即逻辑坐标系和设备坐标系。逻辑坐标系按坐标设置方式 (又称为映射模式)可分为8种,它们的坐标特性如下: 映射模式 逻辑单位 x递增方向 递增方向 MM TEXT 像素 向右 向下 MM LOMETRIC 0.Imm 向右 向上 MM HIMETRIC 0.01mm 向右 向上 MM LOENGLISH 0. linch 向右 向上 MM HIENGLISH 向右 向上 MM TWIPS 1/1440inch
第 10 单元 图形设备接口 - 197 - CDC 类的 SelectObject()函数原型如下: CPen* SelectObject( CPen* pPen ); CBrush* SelectObject( CBrush* pBrush ); virtual CFont* SelectObject( CFont* pFont ); 即 SelectObject()是重载的 CDC 类成员函数。SelectObject()将一个 GDI 对象选入到设 备环境中,新选中的对象将替换原有的同类型对象,然后返回指向被替换的对象的指针。 10.2 绘画模式 在 Windows 中,绘图的最终效果不但取决于画笔和画刷的设置,还可以通过设定绘图 模式来修正。屏幕绘图模式可通过 CDC 的成员函数 SetROP2()设定,其原型为: int SetROP2 ( int nDrawMode ); 其中参数 nDrawMode 为选定的绘图模式,常用模式有: 绘图模式 说明 R2_BLACK 无论画笔色如何,只用黑色绘图; R2_WHITE 无论画笔色如何,只用白色绘图; R2_NOP 无论画笔色如何,用无色笔绘图; R2_NOT 用与背景色相反的颜色绘图; R2_NOTCOPYPEN 用与画笔色相反的颜色绘图; R2_COPYPEN 用画笔色绘图; R2_XORPEN 对画笔色和背景色作异或(XOR)运算。 其中 R2_NOT 模式可保证所绘图形是可见的,即如果画笔色与背景色相同,则以与背景色 相反的颜色作图,避免了所画图形“淹没”在背景中;R2_XORPEN 模式有一种特殊效果, 即对同一条线画两次会起到擦除作用。 该函数的返回值为原来的绘图模式。 10.3 GDI 坐标系 GDI 支持两种类型的坐标系,即逻辑坐标系和设备坐标系。逻辑坐标系按坐标设置方式 (又称为映射模式)可分为 8 种,它们的坐标特性如下: 映射模式 逻辑单位 x 递增方向 y 递增方向 MM_TEXT 像素 向右 向下 MM_LOMETRIC 0.1mm 向右 向上 MM_HIMETRIC 0.01mm 向右 向上 MM_LOENGLISH 0.01inch 向右 向上 MM_HIENGLISH 0.001inch 向右 向上 MM_TWIPS 1/1440inch 向右 向上
第10单元图形设备接口 -198 MM ISOTROPIC 可调整(x=y)可选择 可选择 MM ANISOTROPIC可调整(xl=y)可选择 可选择 注意所有映射模式的坐标原点均在设备输出区域(如窗口客户区或打印纸上的打印 域)的左上角。因此,对于y坐标递增方向向下的映射模式(如 MM TEXT),y坐标值均 为正值,而对于y坐标递增方向向上的映射模式(如 MM LOMETRIC等),所有的y坐标 值均为负值,在编程时要特别注意。 最常用的映射模式是 MM TEXT,这也是缺省设置。在该模式下,坐标原点在客户区 左上角,ⅹ坐标值是向右递增,y坐标值是向下递增,单位值1代表一个像素,与屏幕坐标 系类似。采用除 MM TEXT外的其他映射模式的原因有二:一是欲使程序显示在不同的屏 幕分辨率(如640×480、800×600或1024×768等)下有相近的尺度;二是欲使程序的显 示和打印比例相近(参看13.2:“打印和打印预览”) 设置映射模式,可使用CDC类的 SetMap Mode()成员函数,其原型为 virtual int SetMap Mode( int nMapMode ) 其中参数nMaφ pMode为欲设置的映射模式,返回值为原来的映射模式。 MFC绘图函数均使用逻辑坐标作为位置参数。例如 String str("Hello, MFC!") dc TextOut(10, 10, str, str. GetLengthO) 这里的(10,10)是逻辑坐标而不是像素点数(只是在缺省映射模式 MM TEXT下,正好 与像素点相对应),在输出时GD函数会将逻辑坐标(10,10)依据当前映射模式转化为“设 备坐标”,然后将文字输出在屏幕上 设备坐标以像素点为单位,且ⅹ轴坐标值向右递增,y轴坐标值向下延伸,但原点(0, 0)位置却不限定在工作区左上角。依据设备坐标的原点和用途,可以将 Windows下使用的 设备坐标系统分为三种:客户区坐标系统,窗口坐标系统和屏幕坐标系统 1.客户区坐标系统:客户区坐标系统是最常见的坐标系统,以窗口客户区左上角为原 点(0,0),主要用于窗口客户区绘图输出以及处理窗口的一些消息。鼠标消息 WM LBUTTONDOWN、 WM MOUSEMOVE传给框架的消息参数以及CDC一些用于绘图 的成员都是使用客户区坐标 2.屏幕坐标系统:屏幕坐标系统是另一类常用的坐标系统,以屏幕左上角为原点(0, )。一些与窗口客户区不相关的函数均以屏幕坐标为单位,例如设置和取得光标位置的函数 SetCursor Pos()和 GetCursorPos():由于光标可以在任何一个窗口之间移动,它不属于任 何一个单一的窗口,因此使用屏幕坐标。弹出式菜单使用的也是屏幕坐标。另外, Create window()和 Move window()等函数用于设置窗口相对于屏幕的位置,使用的也是 屏幕坐标系统。 窗口坐标系统:窗口坐标系统以窗口左上角为坐标原点,它包含了窗口控制菜单 标题栏等内容。一般情况下很少在窗口标题栏上绘图,因此这种坐标系统很少使用 MFC提供 ClientToscreen()、 Screen toclient()两个函数用于完成客户区坐标和屏幕 坐标之间的转换工作 void Screen ToClient( LPPoiNT lpPoint )const void Screen To Client( LPRECT lpRect)const Client ToScreen( LPPOINT lpPoint)const; Client ToScreen( LPRECT lpRect )const
第 10 单元 图形设备接口 - 198 - MM_ISOTROPIC 可调整 (x = y) 可选择 可选择 MM_ANISOTROPIC 可调整(x != y) 可选择 可选择 注意所有映射模式的坐标原点均在设备输出区域(如窗口客户区或打印纸上的打印区 域)的左上角。因此,对于 y 坐标递增方向向下的映射模式(如 MM_TEXT),y 坐标值均 为正值,而对于 y 坐标递增方向向上的映射模式(如 MM_LOMETRIC 等),所有的 y 坐标 值均为负值,在编程时要特别注意。 最常用的映射模式是 MM_TEXT,这也是缺省设置。在该模式下,坐标原点在客户区 左上角,x 坐标值是向右递增,y 坐标值是向下递增,单位值 1 代表一个像素,与屏幕坐标 系类似。采用除 MM_TEXT 外的其他映射模式的原因有二:一是欲使程序显示在不同的屏 幕分辨率(如 640×480、800×600 或 1024×768 等)下有相近的尺度;二是欲使程序的显 示和打印比例相近(参看 13.2:“打印和打印预览”)。 设置映射模式,可使用 CDC 类的 SetMapMode()成员函数,其原型为 virtual int SetMapMode ( int nMapMode ); 其中参数 nMapMode 为欲设置的映射模式,返回值为原来的映射模式。 MFC 绘图函数均使用逻辑坐标作为位置参数。例如 CString str(“Hello, MFC!”); dc.TextOut(10, 10, str, str.GetLength()); 这里的(10,10)是逻辑坐标而不是像素点数(只是在缺省映射模式 MM_TEXT 下,正好 与像素点相对应),在输出时 GDI 函数会将逻辑坐标(10,10)依据当前映射模式转化为“设 备坐标”,然后将文字输出在屏幕上。 设备坐标以像素点为单位,且 x 轴坐标值向右递增,y 轴坐标值向下延伸,但原点(0, 0)位置却不限定在工作区左上角。依据设备坐标的原点和用途,可以将 Windows 下使用的 设备坐标系统分为三种:客户区坐标系统,窗口坐标系统和屏幕坐标系统。 1.客户区坐标系统:客户区坐标系统是最常见的坐标系统,以窗口客户区左上角为原 点(0,0),主要用于窗口客户区绘图输出以及处理窗口的一些消息。鼠标消息 WM_LBUTTONDOWN、WM_MOUSEMOVE 传给框架的消息参数以及 CDC 一些用于绘图 的成员都是使用客户区坐标。 2.屏幕坐标系统:屏幕坐标系统是另一类常用的坐标系统,以屏幕左上角为原点(0, 0)。一些与窗口客户区不相关的函数均以屏幕坐标为单位,例如设置和取得光标位置的函数 SetCursorPos()和 GetCursorPos();由于光标可以在任何一个窗口之间移动,它不属于任 何一个单一的窗口,因此使用屏幕坐标。弹出式菜单使用的也是屏幕坐标。另外, CreateWindow()和 MoveWindow()等函数用于设置窗口相对于屏幕的位置,使用的也是 屏幕坐标系统。 3.窗口坐标系统:窗口坐标系统以窗口左上角为坐标原点,它包含了窗口控制菜单、 标题栏等内容。一般情况下很少在窗口标题栏上绘图,因此这种坐标系统很少使用。 MFC 提供 ClientToScreen()、ScreenToClient()两个函数用于完成客户区坐标和屏幕 坐标之间的转换工作。 void ScreenToClient( LPPOINT lpPoint ) const; void ScreenToClient( LPRECT lpRect ) const; void ClientToScreen( LPPOINT lpPoint ) const; void ClientToScreen( LPRECT lpRect ) const;
第10单元图形设备接口 如果用户在窗口客户区移动鼠标或按下鼠标按键,就会得到鼠标位置的设备坐标。在使 用该数据绘图时,需要将其转化为逻辑坐标。CDC类提供了两个成员函数 LPtoDP()和 DPtoLP()完成逻辑坐标和设备坐标之间的转换工作,其中 LPtoDP用于将逻辑坐标转换为 设备坐标,而 DPtoLP()用于将设备坐标转换为逻辑坐标 void LPtoDP( LPPOiNT lpPoints, int n Count =1)const void LPtoDP( LPRECT lpRect )const yoid DPtoLP( LPPOINT lp Points, int n Count=1)const void DPtoLP( LPRECT lpRect )const 但如果采用 MM TEXT的映射模式,设备坐标和逻辑坐标一致,就无需转换了。第9单元 的例题程序均如此 例10-1在窗口中显示一个椭圆,并用鼠标切换该椭圆的图形参数。 说明:建立项目的方法见98:“用 Visual c++集成开发环境开发Wn32应用程序 程序: ∥/ Example10-1:用鼠标切换图形参数 #include /框架窗口类 class CMy Wnd: public CFrameWnd int m color CRect m rectEllipse: public CMy Wndo protected fx msg void OnPaint o afx msg void OnLButtonDown (UINT nFlags, CPoint point) DECLARE MESSAGE MAP O //消息映射 BEGIN MESSAGE MAP(CMyWnd, CFrameWnd ON WM PAINTO ON WM LBUTTONDOWN O END MESSAGE MAP O /框架窗口类的成员函数 CMyWnd: CMyWndO: m rectEllipse(100, 100, 300, 250) m cOlor o void CMyWnd: OnPaint o
第 10 单元 图形设备接口 - 199 - 如果用户在窗口客户区移动鼠标或按下鼠标按键,就会得到鼠标位置的设备坐标。在使 用该数据绘图时,需要将其转化为逻辑坐标。CDC 类提供了两个成员函数 LPtoDP()和 DPtoLP()完成逻辑坐标和设备坐标之间的转换工作,其中 LPtoDP 用于将逻辑坐标转换为 设备坐标,而 DPtoLP()用于将设备坐标转换为逻辑坐标: void LPtoDP ( LPPOINT lpPoints, int nCount = 1 ) const; void LPtoDP ( LPRECT lpRect ) const; void DPtoLP ( LPPOINT lpPoints, int nCount = 1 ) const; void DPtoLP ( LPRECT lpRect ) const; 但如果采用 MM_TEXT 的映射模式,设备坐标和逻辑坐标一致,就无需转换了。第 9 单元 的例题程序均如此。 [例 10-1] 在窗口中显示一个椭圆,并用鼠标切换该椭圆的图形参数。 说 明:建立项目的方法见 9.8:“用 Visual C++集成开发环境开发 Win32 应用程序”。 程 序: // Example 10-1: 用鼠标切换图形参数 #include // 框架窗口类 class CMyWnd: public CFrameWnd { int m_nColor; CRect m_rectEllipse; public: CMyWnd(); protected: afx_msg void OnPaint(); afx_msg void OnLButtonDown(UINT nFlags, CPoint point); DECLARE_MESSAGE_MAP() }; // 消息映射 BEGIN_MESSAGE_MAP(CMyWnd,CFrameWnd) ON_WM_PAINT() ON_WM_LBUTTONDOWN() END_MESSAGE_MAP() // 框架窗口类的成员函数 CMyWnd::CMyWnd():m_rectEllipse(100,100,300,250) { m_nColor = 0; } void CMyWnd::OnPaint() {
第10单元图形设备接口 200- witch(m cOlor) brushNew. CreateSolidBrush(RGB(255, 0, 0)) penNew. CreatePen(PS DASH, 1, RGB(0, 0, 0)) case brushNew. CreateHatchBrush(HS DIAGCROSS, RGB(, 255, 0)) penNew. CreatePen(PS SOLID, 1, RGB (255, 0, 0)) break case brushNew. CreateSolidBrush(RGB(0, 0, 255)) (0,255,0); break pbrushold dc SelectObject(&brushNew) lold ( &pen New) dc SelectObject(pbrushold) void CMyWnd:: OnLButton Down ( UINT nFlags, CPoint point) f(m rectEllipse. PtInRect(point)) /应用程序类 class CMy App: public CWinApp BOOLInitInstance o
第 10 单元 图形设备接口 - 200 - CPaintDC dc(this); CBrush brushNew, *pbrushOld; CPen penNew, *ppenOld; switch(m_nColor) { case 0: brushNew.CreateSolidBrush(RGB(255,0,0)); penNew.CreatePen(PS_DASH, 1, RGB(0,0,0)); break; case 1: brushNew.CreateHatchBrush(HS_DIAGCROSS,RGB(0,255,0)); penNew.CreatePen(PS_SOLID, 1, RGB(255,0,0)); break; case 2: brushNew.CreateSolidBrush(RGB(0,0,255)); penNew.CreatePen(PS_SOLID, 3, RGB(0,255,0)); break; } pbrushOld = dc.SelectObject(&brushNew); ppenOld = dc.SelectObject(&penNew); dc.Ellipse(m_rectEllipse); dc.SelectObject(pbrushOld); dc.SelectObject(ppenOld); } void CMyWnd::OnLButtonDown(UINT nFlags, CPoint point) { if(m_rectEllipse.PtInRect(point)) { m_nColor = (m_nColor+1)%3; InvalidateRect(m_rectEllipse); } } // 应用程序类 class CMyApp: public CWinApp { public: BOOLInitInstance(); };
第10单元图形设备接口 201 /应用程序类的成员函数 BOOL CMyApp: InitInstanceO CMyWnd *kpFrame new CMy Wnd pFrame->Create(0, T("Change the Color of a Ellipse ")) pFrame->ShowWindow(m nCmdShow) pFrame->Update Window O this->m pMainWnd pFr return TRUe //全局应用程序对象 输出:在窗口客户区显示一个椭圆,用鼠标左键点击可以改变它的颜色等设置。 分析:该程序的基本结构仍与例91相同。在由 CFrameWnd类派生的框架窗口类 中添了两个数据成员,一个是椭圆的包含矩形,一个是其颜色参数。这两个数据成员的初始 化在重载的 CMy Wnd类的构造函数中进行 在 On Paint()函数中,根据变量 m n color的值设置画笔和画刷,然后画出椭圆 如果用户按下鼠标左键则触发 OnLButton Down()函数。在 On LButtonDown()函数 中,首先检测鼠标的位置,如果是在椭圆的包含矩形中,则修改数据成员 m n color的值 调用Wnd类的成员函数 Invalidate Rect()的用途是强制更新窗口客户区的内容。我们 知道, OnPaint()函数仅在创建窗口或窗口发生变化的情况下调用,因此为了显示修改过 的效果,就必须强行更新窗口客户区。不过,因为被修改的仅仅是客户区的一小块内容(椭 圆),所以使用 InvalidateRect()函数,该函数仅强制更新指定的矩形区域,这样可以减少 因大面积更新带来的图形抖动影响。如果要更新整个客户区,可使用Wnd类的成员函数 validate()。 本程序中使用缺省的逻辑坐标系 MM TEXT,其特点是其坐标与工作区坐标系统(设 备坐标系)恰好一致。这样,在就避免了在检测鼠标位置时转换坐标,因为鼠标位置用设备 坐标给出,而绘图函数(包括 PtInrect()函数)使用逻辑坐标系。 自学内容 104字体 描述输出文字的字体可用 CFont对象。 CFont对象的使用方法与画笔、画刷类似,也要 定义字体对象,创建字体并保存原来的字体,在文字输出工作结束后恢复原来的字体。创建 字体的 CFont类成员函数的原型为:
第 10 单元 图形设备接口 - 201 - // 应用程序类的成员函数 BOOL CMyApp::InitInstance() { CMyWnd *pFrame = new CMyWnd; pFrame->Create(0,_T("Change the Color of a Ellipse")); pFrame->ShowWindow(m_nCmdShow); pFrame->UpdateWindow(); this->m_pMainWnd = pFrame; return TRUE; } // 全局应用程序对象 CMyApp ThisApp; 输 出:在窗口客户区显示一个椭圆,用鼠标左键点击可以改变它的颜色等设置。 分 析:该程序的基本结构仍与例 9-1 相同。在由 CFrameWnd 类派生的框架窗口类 中添了两个数据成员,一个是椭圆的包含矩形,一个是其颜色参数。这两个数据成员的初始 化在重载的 CMyWnd 类的构造函数中进行。 在 OnPaint()函数中,根据变量 m_nColor 的值设置画笔和画刷,然后画出椭圆。 如果用户按下鼠标左键则触发 OnLButtonDown()函数。在 OnLButtonDown()函数 中,首先检测鼠标的位置,如果是在椭圆的包含矩形中,则修改数据成员 m_nColor 的值。 调用 Wnd 类的成员函数 InvalidateRect()的用途是强制更新窗口客户区的内容。我们 知道,OnPaint()函数仅在创建窗口或窗口发生变化的情况下调用,因此为了显示修改过 的效果,就必须强行更新窗口客户区。不过,因为被修改的仅仅是客户区的一小块内容(椭 圆),所以使用 InvalidateRect()函数,该函数仅强制更新指定的矩形区域,这样可以减少 因大面积更新带来的图形抖动影响。如果要更新整个客户区,可使用 Wnd 类的成员函数 Invalidate()。 本程序中使用缺省的逻辑坐标系 MM_TEXT,其特点是其坐标与工作区坐标系统(设 备坐标系)恰好一致。这样,在就避免了在检测鼠标位置时转换坐标,因为鼠标位置用设备 坐标给出,而绘图函数(包括 PtInRect()函数)使用逻辑坐标系。 自学内容 10.4 字体 描述输出文字的字体可用 CFont 对象。CFont 对象的使用方法与画笔、画刷类似,也要 定义字体对象,创建字体并保存原来的字体,在文字输出工作结束后恢复原来的字体。创建 字体的 CFont 类成员函数的原型为:
第10单元图形设备接口 BOOL CreateFont( int nHeight ∥字符逻辑高度 ∥字体逻辑宽度 ∥出口矢量与X轴的角度 ∥字符基线与X轴的角度 int n Weight ∥字体磅值 bYte iTalic ∥非0则为斜体 BYTE uNderline ∥非0则加下划线 BYTE sTrikeoUt ∥非0则加删除线 BYTE nChar Set ∥此字体的字符集 BYTE nOutPrecision, ∥输出精度 ∥裁剪精度 BYTE qUality, ∥输出质量 BYTE nPitchAndFamily,∥调距和字体族 LPCTSTR lpszFacename);,∥字体的字型名 其中各参数的含义已经注明。下面进一步说明几个重要参数的设置 1. nHeight(字符逻辑高度) 该参数值大于0则高度值转换为设备单位,并与可用字体的单元高度匹配;等于0则使 用缺省字体尺寸:小于0则高度值转换为设备单位,其绝对值与可用字体的字符高度匹配 2. n Width(字体逻辑宽度) 字体字符的平均宽度(逻辑单位)。如果为0,则宽度由系统确定。 3. n Weight(字体磅值) 可取0到1000间的任何值,或用符号常数 FW DONTCARE 0 ∥缺省字体磅值 FW THIN FW EXTRALIGHT 200 FW ULTRALIGHT 200 FW LIGHT 300 FW NORMAL 400 FW REGULAR FW MEDIUM 500 FW SEMIBOLD FW DEMIBOLD FW BOLD 700 FW EXTRABOLD FW ULTRABOLD 800 FW BLACK FW HEAVY 900 4. n CharSet(字符集)
第 10 单元 图形设备接口 - 202 - BOOL CreateFont( int nHeight, // 字符逻辑高度 int nWidth, // 字体逻辑宽度 int nEscapement, // 出口矢量与 X 轴的角度 int nOrientation, // 字符基线与 X 轴的角度 int nWeight, // 字体磅值 BYTE bItalic, // 非 0 则为斜体 BYTE bUnderline, // 非 0 则加下划线 BYTE cStrikeOut, // 非 0 则加删除线 BYTE nCharSet, // 此字体的字符集 BYTE nOutPrecision, // 输出精度 BYTE nClipPrecision, // 裁剪精度 BYTE nQuality, // 输出质量 BYTE nPitchAndFamily, // 调距和字体族 LPCTSTR lpszFacename ); // 字体的字型名 其中各参数的含义已经注明。下面进一步说明几个重要参数的设置。 1.nHeight(字符逻辑高度) 该参数值大于 0 则高度值转换为设备单位,并与可用字体的单元高度匹配;等于 0 则使 用缺省字体尺寸;小于 0 则高度值转换为设备单位,其绝对值与可用字体的字符高度匹配。 2.nWidth(字体逻辑宽度) 字体字符的平均宽度(逻辑单位)。如果为 0,则宽度由系统确定。 3.nWeight(字体磅值) 可取 0 到 1000 间的任何值,或用符号常数: FW_DONTCARE 0 // 缺省字体磅值 FW_THIN 100 FW_EXTRALIGHT 200 FW_ULTRALIGHT 200 FW_LIGHT 300 FW_NORMAL 400 FW_REGULAR 400 FW_MEDIUM 500 FW_SEMIBOLD 600 FW_DEMIBOLD 600 FW_BOLD 700 FW_EXTRABOLD 800 FW_ULTRABOLD 800 FW_BLACK 900 FW_HEAVY 900 4.nCharSet(字符集)
第10单元图形设备接口 203- 可用: ANSI CHARSET 0 DEFAULT CHARSET ∥缺省字符集 SYMBOL CHARSET 2 SHIFTJIS CHARSET OEM CHARSET 5. n Out Precision(输出精度) 可用: OUT CHARACTER PRECIS OUT STRING PRECIS OUT DEFAULT PRECIS ∥缺省输出精度 OUT STROKE PRECIS OUT DEVICE PRECIS OUT TT PRECIS OUT RASTER PRECIS 6. cLip Precision(裁剪精度) 定义在裁减区边界的裁减精度。可用: CLIP CHARACTER PRECIS CLIP MASK CLIP DEFAULT PRECIS ∥缺省裁减精度 CLIP STROKE PRECIS CLIP ENCAPSULATE CLIP TT ALWAYS CLIP LH ANGLES 7. qUality(输出质量) 可用 DEFAULT QUALITY ∥缺省输出质量 DRAFT QUALITY PROOF QUALITY 8. nPitchAndFamily(调距和字体族) 可用: DEFAULT PITCH ∥缺省值 VARIABLE PITCH FIXED PITCH 该函数的返回值为原来的字体。 字体设置是一件比较麻烦的事。当然,在设置某种字体时,可能其中大部分参数都可使 用缺省值。为了确定某个参数的效果,最好是编一简单的程序验证
第 10 单元 图形设备接口 - 203 - 可用: ANSI_CHARSET 0 DEFAULT_CHARSET 1 // 缺省字符集 SYMBOL_CHARSET 2 SHIFTJIS_CHARSET 128 OEM_CHARSET 255 5.nOutPrecision(输出精度) 可用: OUT_CHARACTER_PRECIS OUT_STRING_PRECIS OUT_DEFAULT_PRECIS // 缺省输出精度 OUT_STROKE_PRECIS OUT_DEVICE_PRECIS OUT_TT_PRECIS OUT_RASTER_PRECIS 6.nClipPrecision(裁剪精度) 定义在裁减区边界的裁减精度。可用: CLIP_CHARACTER_PRECIS CLIP_MASK CLIP_DEFAULT_PRECIS // 缺省裁减精度 CLIP_STROKE_PRECIS CLIP_ENCAPSULATE CLIP_TT_ALWAYS CLIP_LH_ANGLES 7.nQuality(输出质量) 可用: DEFAULT_QUALITY // 缺省输出质量 DRAFT_QUALITY PROOF_QUALITY 8.nPitchAndFamily(调距和字体族) 可用: DEFAULT_PITCH // 缺省值 VARIABLE_PITCH FIXED_PITCH 该函数的返回值为原来的字体。 字体设置是一件比较麻烦的事。当然,在设置某种字体时,可能其中大部分参数都可使 用缺省值。为了确定某个参数的效果,最好是编一简单的程序验证一下
第10单元图形设备接口 可以使用 LOGFONT类型的对象存储某字体的各项参数。 LOGFONT是一结构体类型, 其定义为: typedef struct tagLOGFONT i LONG IfHeight ∥字体逻辑高度 LONG Ifwidth ∥字体逻辑宽度 LONG IfEscapement ∥输出字符行与X轴的角度 LONG IfOrientation ∥字符基线与X轴的角度 LONG IfWeight ∥字体磅值 BYTE Ifltalic ∥非0则为斜体 BYTE IfUnderline ∥非0则加下划线 BYTE IfStrikeOut ∥/非0则加删除线 BYTE IfChar Set ∥/此字体的字符集 BYTE IfOut Precision ∥输出精度 BYTE IfClip Precision ∥裁减精度 BYTE IfQuality ∥输出质量 BYTE IfPitchAnd Family: ∥调距和字体族 TCHAR IfFace Name[LF FACESIZE],∥字体的字型名 LOGFONT 如果已经声明了一个 LOGFONT类型的对象,则也可据其建立相应的字体。方法是使用 CFont 类的成员函数 Create FontIndirect()。其原型为: BOOL CreateFontIndirect(const LOGFONT* lpLogFont 其中参数1 pLogFont是一指向存有字体参数对象的指针 10.5库存图形对象 在 Windows的GD中,包含一些预定义的图形对象,无需用户去创建,马上就可以拿 来使用。这些对象称作库存( Stock)对象。库存对象包括画笔、画刷和字体等。创建库存 对象可使用 CGdiObject类的成员函数 CreateStockObject(),其原型为 BOOL Create StockObject( int nIndex 其中参数 nIndex指定要创建的图形对象。常用的图形对象有: 图形对象 说明 BLACK PEN 黑笔 NULL PEN 空笔,不画线或边框 WHITE PEN 白笔 BLACK BRUSH 黑色刷子 WHITE BRUSH 白色刷子
第 10 单元 图形设备接口 - 204 - 可以使用 LOGFONT 类型的对象存储某字体的各项参数。LOGFONT 是一结构体类型, 其定义为: typedef struct tagLOGFONT { LONG lfHeight; // 字体逻辑高度 LONG lfWidth; // 字体逻辑宽度 LONG lfEscapement; // 输出字符行与 X 轴的角度 LONG lfOrientation; // 字符基线与 X 轴的角度 LONG lfWeight; // 字体磅值 BYTE lfItalic; // 非 0 则为斜体 BYTE lfUnderline; // 非 0 则加下划线 BYTE lfStrikeOut; // 非 0 则加删除线 BYTE lfCharSet; // 此字体的字符集 BYTE lfOutPrecision; // 输出精度 BYTE lfClipPrecision; // 裁减精度 BYTE lfQuality; // 输出质量 BYTE lfPitchAndFamily; // 调距和字体族 TCHAR lfFaceName[LF_FACESIZE]; // 字体的字型名 } LOGFONT; 如果已经声明了一个LOGFONT类型的对象,则也可据其建立相应的字体。方法是使用CFont 类的成员函数 CreateFontIndirect()。其原型为: BOOL CreateFontIndirect(const LOGFONT* lpLogFont ); 其中参数 lpLogFont 是一指向存有字体参数对象的指针。 10.5 库存图形对象 在 Windows 的 GDI 中,包含一些预定义的图形对象,无需用户去创建,马上就可以拿 来使用。这些对象称作库存(Stock)对象。库存对象包括画笔、画刷和字体等。创建库存 对象可使用 CGdiObject 类的成员函数 CreateStockObject(),其原型为: BOOL CreateStockObject( int nIndex ); 其中参数 nIndex 指定要创建的图形对象。常用的图形对象有: 图形对象 说明 BLACK_PEN 黑笔 NULL_PEN 空笔,不画线或边框 WHITE_PEN 白笔 BLACK_BRUSH 黑色刷子 WHITE_BRUSH 白色刷子