540 likes | 753 Views
第 8 章 图形图像处理. 1. 设备环境( DC )的概念。 2. 常用的几个设备环境类如 CPaintDC 、 CClientDC 、 CWindowDC 和 CMetaFileDC 类的主要特点及它们在使用方法上的区别。 3.GDI 的概念及常用的绘图设备类如 CGdiObject 、 CPen 、 CBrush 、 Cfont 和 CBitmap 等的对象的创建和将其引入到设备环境中的方法。 4.Windows 下的坐标映像方式和特点以及如何设置坐标映像方式。 5. 几种常见的 Windows 的坐标映像方式下的坐标转换方法。
E N D
第8章 图形图像处理 • 1.设备环境(DC)的概念。 • 2.常用的几个设备环境类如CPaintDC、CClientDC、CWindowDC和CMetaFileDC类的主要特点及它们在使用方法上的区别。 • 3.GDI的概念及常用的绘图设备类如CGdiObject、CPen、CBrush、Cfont和CBitmap等的对象的创建和将其引入到设备环境中的方法。 • 4.Windows下的坐标映像方式和特点以及如何设置坐标映像方式。 • 5.几种常见的Windows的坐标映像方式下的坐标转换方法。 • 6.几种常见的基本图形元素如点、直线、矩形和文字等的绘制方式。
8.1 设备环境(DC) • (1)在Windows中,显示工作是基于设备环境的。所谓设备环境(DC)是一种Windows数据结构,该结构包含应用程序设备输出时所需要的信息。 • (2)在使用任何绘图函数之前必须建立一个设备环境对象。 • (3)在Visual C++ 6.0的MFC中提供了设备环境类CDC,它封装了绘图所需要的所有函数,其中包括了大多数的Windows API中的GDI函数。
8.1 设备环境(DC) • 8.1.1 设备环境类 • 1. CDC类 • (1)CDC类是CObject类的派生类,也是所有设备环境类的基类。CDC类定义了一个设备描述对象,并提供了对设备描述对象进行操作的成员函数以及对与窗口客户区有关的显示区进行操作的成员函数。 • (2)CDC类提供的成员函数可以用于操作设备描述对象、使用绘图工具、选择图形设备界面,以及操作颜色和调色板,还用于取得和设置绘图属性、映射方式、视图和窗口范围的操作、坐标的转换、区域的使用、剪取、画线以及绘制图形和文字等操作。
8.1 设备环境(DC) • 2. CPaintDC类 • (1)CPaintDC类是CDC类的一个派生类,该类一般用在响应WM_PAINT消息的函数OnPaint()中。 • (2)WM_PAINT消息是当窗口的某个区域需要重画时激发的窗口消息。当程序中的消息循环接到WM_PAINT消息时就自动调用消息处理函数OnPaint(),如果在OnPaint函数内定义了CPaintDC类的对象,通过这个类对象就可以使用CDC类的成员函数完成视图客户区中的图形绘制操作。
8.1 设备环境(DC) • 3. CClientDC类 • CClientDC类也是CDC类的派生类。它只能在窗口的客户区(即窗口中除了边框、标题栏、菜单栏以及状态栏外的中间部分)中进行绘图,坐标点(0,0)通常指的是客户区的左上角。它的构造函数调用GegDC函数,而析构函数调用ReleaseDC函数。 • 4. CWindowDC类 • CWindowDC类也是CDC类的派生类。其成员函数可以在窗口的客户区和非客户区(即窗口的边框、标题栏、菜单栏以及状态栏)中绘图,坐标点(0,0)是指整个屏幕的左上角。同CClientDC类一样,它的构造函数调用GegDC函数,而析构函数调用ReleaseDC函数。
8.1 设备环境(DC) • 5. CMdtaFileDC类 • CMetaFileDC类提供了一个面向Windows图元文件的设备环境,封装了在一个Windows图元文件中绘图的方法。图元文件是一个与设备无关的图片的集合,由于它对图像的保存比像素更精确,因而往往在要求较高的场合下使用,例如AutoCAD的图形保存等。
8.1 设备环境(DC) • 8.1.2 几个设备环境类的主要差别 • 1. CWindowDC类与CPaintDC 、CClientDC类的区别 • 其区别主要有以下两个方面: • (1)用CPaintDC 和CClientDC类的对象绘制图形时,绘制区只能在客户区,而不能在非客户区;而CwindowDC类既可以在窗口的客户区也可以在非客户区进行图形绘制。 • (2)在CWindowDC绘图类下,坐标系是建立在整个屏幕上的,在像素坐标方式下,坐标原点在屏幕的左上角;而在CPaintDC和CClientDC绘图类下,坐标系是建立在客户区上的,在像素坐标方式下,坐标原点在客户区的左上角。
8.1 设备环境(DC) • 2. CPaintDC类与CClientDC类的区别 • CPaintDC类的对象应用在OnPaint函数中,以响应Windows的WM_PAINT消息;而CClientDC类的对象应用在非响应消息WM_PAINT的情况下。 • CPaintDC类响应WM_PAINT消息,并自动完成绘制,这对维护图形的完整性有着重要的作用。CClientDC类可以实时地将图形绘制到屏幕上,不需要重画;而如果用CPaintDC类的对象完成同样的工作,只能发出消息让屏幕上包含这条直线的区域重画,以把这条直线绘制到屏幕上。
8.1 设备环境(DC) • 8.1.3 设备环境类的使用方法 • 1. CDC类 • 因为CDC类不能用窗口对象指针初始化对象,所以,一般不直接定义对象。 • 2. CPaintDC类 • CPaintDC 类一般用在窗口类OnPaint函数中,可采用如下代码定义一个CPaintDC类对象: • CPaintDC dc(this); • 以上代码定义了一个CPaintDC类的对象dc,并用当前的窗口对象指针this对对象进行了初始化。CClientDC和CWindowDC类也采用这样的方法。 • 3. CClientDC类 • 可利用以下代码定义一个对象:CClientDC dc(this); • 4. CWindowDC 类 • 利用以下代码创建一个CWindowDC类的对象:CWindowDC dc(this);
8.2 绘图设备类 • Windows为设备环境提供了各种各样的绘图工具,如【画笔】、【画刷】以及【字体】等。在MFC中封装了这些工具,这些类称为GDI类,它们有一个共同的抽象基类CGdiObject,可以将这些绘图设备类创建的对象选入到设备环境中,完成有关的操作。 • 在MFC中主要的绘图设备类有:CGdiObject、CPen、CBrush、CFont、CBitmap、CRgn和CPalette等。 • 在选择绘图设备类对象(GDI对象)进行绘图时,一般可按下列步骤进行: • (1)定义一个GDI对象,然后调用相应的函数(如CreatePen、CreateSolidBrush等)创建此GDI对象。 • (2)将已构造出的GDI对象利用设备环境类对象的成员函数SelectObject选入到当前环境中,并同时将原来的GDI对象保存起来。 • (3)绘图结束后,恢复当前设备环境中原来的GDI对象。 • 注意:在Windows系统中包含了一些库存的GDI对象,在第(3)步中可直接利用设备环境类(CDC)的成员函数SelectStockObject将一个Windows库存的GDI对象选入,系统可自动将原来选入的GDI对象从设备环境中分离出来。
8.2 绘图设备类 • 8.2.1 CGdiObject类 • CGdiObject类派生于CObject类,它是CGdiObject、CPen、CBrush、Cfont和CBitmap等的基类。用户不能直接生成一个CGdiObject类,而必须在它的某种设备继承类中生成一个CGdiObject类的派生类。 • 8.2.2 CPen类 • CPen类是CGdiObject类的一个派生类,它封装了Windows图形设备接口(GDI)中有关画笔的操作。CPen类的定义如下: • class CPen: public CGdiObject • { • DECLARE_DYNAMIC(CPen) • public:
8.2 绘图设备类 • static CPen* PASCAL FromHandle(HPEN hpen); • // 构造函数 • CPen( ); • CPen(int nPenStyle, int nWidth,COLORREF crColor); • #ifndef_MAC • CPen(int nPenStyle, int nWidth, const LOGBRUSH * pLogBrush,int nStyleCount=0, const DWORD * lpStyle=NULL); • #endif • BOOL CreatePen(int nPenStyle, int nWidth, COLORREF crColor); • #ifndef_MAC • BOOL CreatePen(int nPenStyle, int nWidth, const LOGBRUSH * pLogBrush, • int nStyleCount=0, const DWORD * lpStyle=NULL); • #endif • BOOL CreatePenIndirect(LPLOGPEN lpLogPen); • //其他部分省略 • };
8.2 绘图设备类 • 8.2.2.1 创建CPen对象 • 创建一个CPen对象可以有以下几种方法: • (1)定义一个CPen对象,用其成员函数CreatePen或CreatePenIndirect对其进行初始化。如: • CPen pen; • Pen.CreatePen(PS_SOLID,1,RGB(255,0,0)); • (2)定义一个CPen对象,并一次性地初始化它的所有参数。如: • CPen pen(PS_SOLID,1,RGB(255,0,RGB(255,0,0)); • (3)动态地创建一个CPen对象。如: • CPen *pen; • Pen=new CPen(PS_SOLID,1,RGB(255,0,0)); • 在一个函数中多次创建一个CPen对象时可以采用这种方法。应用这种方法时,特别注意操作完毕后要删除分配的CPen对象,即: • delete pen;
8.2 绘图设备类 线 型 风 格 PS_SOLID 创建一个实线画笔 PS_DASH 创建一个虚线画笔 PS_DOT 创建一个点线画笔 PS_DASHDOT 创建一个虚线和点线交替的画笔 PS_DASHDOTDOT 创建一个虚线和双点线交替的画笔 PS_NULL 创建一个空的画笔 PS_INSIDEFRAME 创建一个在封闭矩形框中使用的画笔 • 参数nPenStyle用于设置画笔画线的线型其取值如下表:
8.2 绘图设备类 • 注意:线型PS_DASH、PS_DOT、PS_DASHDOT和PS_DASHDOTDOT只有在画笔宽度为1个逻辑单位时才有效。 • 参数nWidth:设置以逻辑单位衡量的线宽,如果nWidth为0,则设备自动将画笔设置为一个像素宽,而不管当前的映射方式。 • 参数crColor:设置画笔的颜色,其颜色通过RGB宏来确定: • COLORREF RGB(cRed,cGreen,CBlue); • 参数cRed、cGreen、CBlue分别指定红、绿、蓝3色的相对亮度,每个参数均可以被赋予0到255之间的值。
8.2 绘图设备类 • 8.2.2.2 在设备环境中选入画笔 • 已创建的画笔可以利用CDC类对象的成员函数SelectObject将其选入到当前设备环境中,如: • void OnDraw(CDC * pDC) • { • CPen pen(PS_SOLID,1,RGB(255,0,0)); • CPen * pOldPen=pDC->SelectObject(&pen); • ……//省略各种绘制操作代码 • pDC->SelectObject(pOldPen); • }
8.2 绘图设备类 • 8.2.3 CBrush类 • CBrush类是CGdiObject类的一个派生类,它封装了Windows图形设备界面(GDI)中有关画刷的操作。CBrush类的用法与CPen类似。
8.2 绘图设备类 • 8.2.3.1 创建CBrush对象 • 利用CBrush类的构造函数可创建Cbrush对象。 • 1. 实心画刷 • 用实心画刷进行图形填充时,以这种画刷的颜色实心填充。其创建方法如下: • (1)定义CBrush对象,用函数CreateSolidBrush对对象进行初始化。 • CBrush brush; • brush.CreateSolidBrush(RGB(255,0,0)); • (2)定义CBrush类对象,并利用构造函数对对象的参数进行初始化。 • CBrushbrush(RGB(255,0,0)); • (3)动态创建。用这种方法定义时,在操作完成后要删除创建的CBrush对象。 • CBrush *brush; • Brush=new CBrush(RGB(255,0,0)); • …… • delete brush;
影 线 风 格 8.2 绘图设备类 HS_BDIACONAL 建立一个45°网格线的画刷(从右向左) HS_CROSS 建立一个水平和垂直交叉网格线的画刷 HS_DIAGCROSS 建立一个两条45°垂直交叉网格线的画刷 HS_FDIAGONAL 建立一个45°网格线的画刷(从左向右) HS_HORIZONTAL 建立一个水平网格线的画刷 HS_VERTICAL 建立一个垂直网格线的画刷 • 2. 影线画刷 • 影线画刷不是用画刷的颜色实心填充图形,而是用不同的阴影图案来填充,填充方式如下表。
8.2 绘图设备类 • 影线画刷的创建方法同实心画刷一样: • (1)定义对象,用函数初始化。如: • CBrush brush; • brush.CreateSolidBrush(PS_SOLID,RGB(255,0,0)); • (2)一次性创建。如: • CBrush brush(HS_HORIZONTAL,RGB(255,0,0)); • (3)动态创建。如: • 用这种方法创建的CBrush对象,在操作完成后要删除CBrush对象。 • CBrush * brush; • Brush=new CBrush(HS_HORIZONTAL,RGB(255,0,0)); • …… • delete brush;
8.2 绘图设备类 • 3. 位图画刷 • 位图画刷是用位图图像来填充图形的。函数CreatPatternBrush用来初始化一个位图画刷。以下代码创建一个位图画刷(其中,pBitmap指向一个位图对象): • CBrush brush; • brush.CreatPatternBrush(pBitmap);
8.2 绘图设备类 • 8.2.3.2 在设备环境中选入画刷 • 在设备环境中选入画刷,即CBrush对象的操作是与选入画笔的操作相同的。如: • void OnDraw(CDC * pDC) • { • CBrush brush(HS_CROSS,RGB(255,0,0)); • CBrush* pOldBrush=Pdc->SelectObject(&brush); • ……//省略以下的绘制操作 • pDC->SelectObject(pOldBrush); • }
8.2 绘图设备类 • 8.2.4 CFont类及创建CFont类对象的方法 • CFont类是CGdiObject类的一个派生类,它封装了逻辑字体及方法。 • 8.2.4.1 创建CFont对象 • CFont类只有一个构造函数,在定义了一个CFont类对象之后,必须用成员函数CreateFont或CreateFontIndirect来初始化CFont对象的参数。 • CreateFont函数的参数非常多,可查阅MSDN。
8.2 绘图设备类 • 8.2.4.2在设备环境中选入字体 • 下面介绍创建CFont对象和在设备环境中选入字体的过程。void CDrawView::OnDraw(CDC * pDC) • { • Cfontfont; • font.CreateFont(30,15,0,0,200,0,0,0,255,0,0,2,DEFAULT_PITCH,”VC”); • CFont* pOldFont= pDC->SelectObject(&font); • ……//省略进行文字绘制的部分 • pDC->SelectObject(pOldFont); • }
8.2 绘图设备类 • 8.2.5 CBitmap类 • 和Cpen、CBrush类一样,CBitmap类是CGdiObject类的派生类,它封装了使用Windows GDI进行图形绘制中关于位图的操作。 • 在CBitmap类中重载了两个LoadBitmap函数,用于加载位图资源: • (1)通过资源的ID号加载一个位图资源。其定义如下: • BOOL LoadBitmap(UINT nIDResource); • (2)LoadBitmap的另一种形式用于加载位图文件资源,如: • CString m_str; • CBitmap m_bitmap; • …… • CString sFilter=”Bitmap Files(* .bmp)|*.bmp||”; • CFileDialog m_Dlg(TRUE,NULL, NULL, OFN_HIDEREADONLY | • OFN_OVERWRITEPROMPT,(LPCTSTR)sFilter,NULL); • m_Dlg.DoModal( ); • m_str=m_Dlg.GetPathName( ); • m_Bitmap.LoadBitmap(_T(m_str)); • 也可以使用位图文件的绝对路径作为参数直接调用位图文件。
8.3 坐标映射方式 • 在Visual C++ 6.0中进行Windows图形应用程序设计时,可以采用多种不同的坐标映射方式,即不同的坐标系。 • 8.3.1 Windows映像方式及其设置方法 • 8.3.1.1 Windows映像方式 • Windows映像方式就是Windows下的逻辑坐标方式。一个实际物理屏幕是由像素组成的。 • 为了方便各种情况下的程序开发和减轻程序开发的负担,Windows提供了几种映像方式,每一种映像方式提供不同的测量单位和坐标原点。详见下表:
映像方式 映像识别码 逻辑单位 X和Y轴正向 8.3 坐标映射方式 MM_TEXT 1 Pixels 右下 MM_LOMETRIC 2 0.1mm 右上 MM_HIMETRIC 3 0.01mm 右上 MM_LOENGLISH 4 0.1inch 右上 MM_HIENGLISH 5 0.01inch 右上 MM_TWIPS 6 1/1440inch 右上 MM_ISOTROPIC 7 可变(x等于y) 变化的 MM_ANISOTROPIC 8 可变(x不等于y) 变化的
8.3 坐标映射方式 • 8.3.1.2 Windows映像方式的设置方法 • 在MFC应用程序中,通过调用CDC类的SetMapMode()函数来设置映像方式。如: • pDC->SetMapMode(n); • 其中,n是在上表中列出的映像方式的识别码。 • 该函数的原型为: • virtual int SetMapMode( int nMapMode );
8.3 坐标映射方式 • 8.3.2 逻辑坐标和设备坐标的转换 • 所谓设备坐标是针对屏幕或其他显示设备而言的。以屏幕为例,其原点在屏幕上的左上角;X轴的正方向向右;Y轴的正方向向下;坐标单位为像素。 • 而逻辑坐标是在内存中虚拟的一个坐标系,其原点在屏幕的左上角,X轴的正方向向右,Y轴的正方向向上,其单位随着映像方式的不同而改变。
8.3 坐标映射方式 • 8.3.2.1 设备无关性 • Windows系统提供了坐标映像方式,并实现了设备无关性。所谓设备无关性指的是只要设定了映像方式,那么就会在不同的设备上显示出同样大小的图形。 • 对于MM_TEXT映像方式来说,因为其单位是像素且长度不固定(即一个像素所占的实际长度随着设备的不同而不同),所以,在不同的显示和输出设备上不能保证其图形的大小一样。
8.3 坐标映射方式 • 8.3.2.2 逻辑坐标和像素的转换方法 • 为了完成在各种映像方式下逻辑坐标和设备坐标的转换,VC中提供了两个成员函数: • DPtoLP(LPPOINT lpPoints); //实现从设备坐标转换到逻辑坐标 • LPtoDP(LPPOINT lpPoints); //实现从逻辑坐标转换到设备坐标 • 如: • CPoint point; • point.x=50; • point.y=50; //给点point赋一坐标值 • PDC->DPtoLP(&point) //将点point从设备坐标转换成逻辑坐标 • (1)大多数的CDC类的成员函数要以逻辑坐标作为参数。 • (2)CWnd类的成员函数要以设备坐标作为参数。 • (3)所有选中测试操作和区域的定义要以设备坐标来表示。 • (4)将一些长期使用的坐标值用逻辑坐标来保存。
8.4 窗口和视口 • 8.4.1 窗口和视口的概念 • 窗口指的是虚拟存在的一个屏幕,而视口指的是在屏幕上看到的视图客户区域。在Windows中绘制图形时,并不是把图形直接绘制到屏幕上,而是以各种映像方式下的逻辑坐标系将图形绘制到虚拟的窗口中,然后再将这个窗口中的内容映像到视口中。如果是映像到屏幕上就实现了图形的显示;如果是映像到打印机等输出设备上就实现了图形的打印输出。 • 因此,窗口原点、视口原点和坐标系中的原点3者的概念是不同的。窗口原点和视口原点指的是同一个点在窗口逻辑坐标和视口设备坐标系的坐标值,它决定了图形由窗口映射到视口时的相对位置。
8.4 窗口和视口 • 8.4.2 窗口和视口有关的操作函数 • 在CWnd类中与窗口和视口有关的操作函数如下: • 1. SetWindowOrg函数 • SetWindowOrg函数用来设置一个与设备环境有关的窗口原点。 • CPoint SetWindowOrg(int x,int y); • CPoint SetWindowOrg(POINT point); • 2. SetViewportOrg函数 • SetViewportOrg函数用来设置一个与设备环境有关的视口原点。 • CPoint SetViewportOrg(int x,int y); • CPoint SetViewportOgr(POINT point);
8.4 窗口和视口 • 3. SetWindowExt函数 • SetWindowExt函数用来设置与设备环境有关的窗口在x和y方向的幅度。只有在MM_ISOTROPIC映像方式下该函数才有效。 • virtual CSize SetWindowExt(int cx,int cy); • virtual CSize SetWindowExt(SIZE size); • 4. SetViewportExt函数 • SetViewportExt函数用来设置与设备环境有关的视口在x和y方向的幅度。只有在MM_ISOTROPIC映像方式下该函数才有效。 • virtual CSize SetViewporExt(int cx,int cy); • virtual CSize SetViewporExt(SIZE size); • 必须注意,在MM_ISOTROPIC映像方式下,必须先设置窗口幅度,再设置视口幅度。
8.4 窗口和视口 • 8.4.3 窗口逻辑坐标和视口设备坐标的转换 • 窗口和视口的作用是为了实现设备无关性。 • 8.4.3.1 逻辑坐标和设备坐标的转换方法 • 假定一个点在窗口逻辑坐标为(x1,y1),在视口设备像素坐标为(x2,y2),在两个坐标系Y轴同向的情况下,根据在窗口和视口中这个点到原点的距离相等,则有如下转换关系: • (x1-a1)=(x2-a2)*n • (y1-b1)=(y2-b2)*n • 在两个坐标系Y轴反向的情况下,则有如下的转换关系: • (x1-a1)=(x2-a2)*n • (y1-b1)=-(y2-b2)*n
8.4 窗口和视口 • 8.4.3.2 MM_TEXT映像方式的坐标转换 • 在MM_TEXT映像方式下,因为在窗口和视口中都采用像素坐标,所以n等于1。依据以上讨论的坐标转换公式可得到窗口逻辑坐标到视口设备坐标的转换关系: • x2=x1-a1+a2; • y2=y1-b1+b2; • 同样,可以得到视口设备坐标到窗口逻辑坐标的转换公式: • x1=x2+a1-a2; • y1=y2+b1-b2;
8.4 窗口和视口 • 8.4.3.3 MM_LOMETRIC等4种映像方式下的坐标转换 • 这4种坐标映像方式除了逻辑坐标单位不一样外,其他方面都一样,现在就以MM_LOMETRIC映像方式为例,讨论这4种映像方式下的坐标转换问题。 • 因为MM__LOMETRIC映像方式逻辑坐标与设备坐标Y轴反向,所以得到逻辑坐标到设备坐标的转换公式为: • x2=(x1-a1)/n+a2; • y2=-(y1-b1)/n+b2; • 在MM_LOEMTRIC等4种映像方式下,虽然移动窗口原点和视口原点都可以达到移动图形的目的,但移动量是不一样的。移动窗口原点时,移动量是以逻辑坐标为单位的;而移动视口原点时,移动量是以设备坐标(像素)为单位的。
8.4 窗口和视口 • 8.4.3.4 MM_ISOTROPIC和MM_ANISOTROPIC映像方式的坐标转换 • 在这两种映像方式下,映像后图形的大小要发生变化,视口中的坐标也不再以像素为单位,而窗口中的逻辑坐标则是以像素为单位。 • 在MM_ISOTROPIC映像方式下,x和y两方向同比例缩放,而在MM_ANISOTROPIC映像方式下,允许两方向不同比例放缩。
8.5 设置绘图模式 • 绘图模式指定了画笔颜色和被填充物体内部颜色是如何与显示平面的颜色相混合的。 • 绘图模式只能应用于光栅类设备,而不能用于矢量设备。 • 设置绘图模式是利用CDC类的成员函数SetROP2来完成的,该函数的原型为: • int SetROP2( int nDrawMode ); • 其中:参数nDrawMode表示新的绘图模式,该函数的返回值是原先的绘图模式。能够采用的绘图模式如下表。
绘图模式取值 含 义 R2_BLACK 像素总是黑色 R2_WHITE 像素总是白色 R2_NOP 像素颜色保持不变 R2_NOT 像素颜色为屏幕颜色的反色 R2_COPYPEN 像素颜色为画笔的颜色 R2_NOTCOPYPEN 像素颜色为画笔颜色的反色 R2_MERGEPENNOT 像素颜色是画笔的颜色与屏幕颜色反色的组合 R2_MASKPENNOT 像素颜色是画笔的颜色与屏幕颜色的反色中共有颜色的组合 R2_MERGENOTPEN 像素颜色是屏幕颜色和画笔颜色的反色的组合 R2_MASKNOTPEN 像素颜色是屏幕颜色和画笔颜色的反色中共有颜色的组合 R2_MERGEPEN 像素颜色是屏幕颜色与画笔颜色的组合 R2_NOTMERGEPEN 像素颜色是屏幕颜色和画笔颜色的组合颜色的组合 R2_MASKPEN 像素颜色是画笔颜色和屏幕颜色中共有的颜色的组合 R2_NOTMASKPEN 像素颜色是画笔颜色和屏幕颜色中共有的颜色的组合颜色的反色 R2_XORPEN 像素颜色是既属于画笔颜色又属于屏幕颜色,但并不是两种颜色的公共部分的组合颜色 R2_NOTXORPEN 像素颜色是既属于画笔颜色又属于屏幕颜色,但并不是两种颜色的公共部分的组合颜色的反色
8.6 图形元素的绘制 • 所谓图形元素主要是指点、直线、曲线和文字等。在Visual C++的MFC的设备环境类CDC中提供了相应的成员函数来完成这些基本图形元素的绘制工作。 • 8.6.1 画点 • 利用CDC类的成员函数SetPixel来完成点的绘制工作,该函数的原型为: • COLORREF SetPixel( int x, int y, COLORREF crColor ); • COLORREF SetPixel( POINT point, COLORREF crColor ); • 其中,参数x、y及point均表示逻辑坐标系下所要绘制的点的坐标值,参数crColor表示要绘制的点的颜色。该函数的返回值为实际绘制点的RGB颜色值。
8.6 图形元素的绘制 • 8.6.2 画直线 • 利用CDC类的成员函数LineTo来完成直线的绘制工作,该函数的原型为: • BOOL LineTo( int x, int y ); • BOOL LineTo( POINT point ); • 其中,参数x、y和point是指要画直线的终点端点坐标值。如果绘制直线成功,则该函数返回非零值;否则,返回0。 • 该函数的功能是从当前点为直线的起始点、以(x,y)或point为终点画一条直线。 • 还有一个与画线有关的CDC类的成员函数MoveTo,该函数的原型为: • CPoint MoveTo( int x, int y ); • CPoint MoveTo( POINT point );
8.6 图形元素的绘制 • 8.6.3 画矩形 • 利用CDC类的成员函数Rectangle来完成矩形的绘制工作,该函数的原型为: • BOOL Rectangle( int x1, int y1, int x2, int y2 ); • BOOL Rectangle( LPCRECT lpRect ); • 其中,参数x1、y1是要绘制的矩形左上角的坐标,x2、y2是矩形右下角的坐标。参数lpRect指定要绘制的矩形区域。
8.6 图形元素的绘制 • 8.6.4 画圆角矩形 • 利用CDC类的成员函数RoundRect来完成圆角矩形的绘制工作,该函数的原型为: • BOOL RoundRect( int x1, int y1, int x2, int y2, int x3, int y3 ); • BOOL RoundRect( LPCRECT lpRect, POINT point ); • 其中,参数x1、y1指定圆角矩形左上角的坐标,参数x2、y2指定圆角矩形右下角的坐标,x3表示用来画圆角的椭圆的宽度,y3表示该椭圆的高度。 • 8.6.5 画扇形 • 利用CDC类的成员函数Pie来完成扇形的绘制工作,该函数的原型为: • BOOL Pie( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 ); • BOOL Pie( LPCRECT lpRect, POINT ptStart, POINT ptEnd ); • 各参数的含义可参见圆角矩形。
8.6 图形元素的绘制 • 8.6.6 画多边形 • 利用CDC类的成员函数Polygon来完成多边形的绘制工作,该函数的原型为: • BOOL Polygon( LPPOINT lpPoints, int nCount ); • 其中,参数lpPoints是一个指向多边形各顶点坐标的矩阵,参数nCount表示多边形的顶点总数。 • 8.6.7 绘制文本 • 利用CDC类的成员函数TextOut可完成文字的绘制输出工作,该函数的原型为: • virtual BOOL TextOut( int x, int y, LPCTSTR lpszString, int nCount ); • BOOL TextOut( int x, int y, const CString& str ); • 其中,参数x、y表示输出文字的起始坐标位置,lpszString或str表示要输出的文字,nCount表示输出lpszString所指出的字符串中的字符个数。
8.6 图形元素的绘制 • 与文字的输出有关系的CDC类的成员函数还有: • 输出文字: • virtual int DrawText( LPCTSTR lpszString, int nCount, LPRECT lpRect, UINT nFormat ); • int DrawText( const CString& str, LPRECT lpRect, UINT nFormat ); • 设置文字输出的颜色: • virtual COLORREF SetTextColor( COLORREF crColor ); • 设置文字的对齐方式: • UINT SetTextAlign( UINT nFlags ); • 设置文字间输出的间隙 : • int SetTextCharacterExtra( int nCharExtra );
8.7 在视图中交互绘图 • 本例的基本思想是:首先创建一个SDI应用程序,当程序运行时,把鼠标指针移动到窗口客户区中,则鼠标光标的形状呈十字形,当按下鼠标左键并在视图窗口中拖动到另外一点时放开鼠标,则可以在按下鼠标的位置到放开鼠标时的位置间画一条直线。 • 步骤1:启动Visual C++ 6.0。 • 步骤2:创建一个单文档的应用程序框架。 • 步骤3:在视图类中添加4个成员变量,它们分别是: • m_Drag变量,是一个标志变量,用于表示目前用户是否正在拖动鼠标。 • m_Cursor变量,用于存放鼠标光标形状的句柄。 • m_StartPoint变量,用于记录当用户按鼠标左键时的光标所在位置的坐标。 • m_OldPoint变量,用于存放光标的当前位置。
8.7 在视图中交互绘图 • 步骤4:在视图类的构造函数中加入以下代码来对其成员变量m_Drag和m_Cursor进行初始化。 • CDrawView::CDrawView() • { • // TODO: add construction code here • m_Drag=0; • m_Cursor=AfxGetApp()->LoadStandardCursor(IDC_CROSS); • } • 步骤5:利用ClassWizard向导向视图类CDrawView中添加消息处理函数。在此,需要处理的3个消息是:按下鼠标时的WM_LBUTTONDOWN消息、移动鼠标时的WM_MOUSEMOVE消息和放开鼠标时的WM_LBUTTONUP消息。
8.7 在视图中交互绘图 • 步骤5:对消息WM_LBUTTONDOWN进行消息映射并编写消息处理函数的代码,如下所示: • void CDrawView::OnLButtonDown(UINT nFlags, CPoint point) • { • m_StartPoint=point; • m_OldPoint=point; • SetCapture(); • m_Drag=1; • RECT Rect; • GetClientRect(&Rect); • ClientToScreen(&Rect); • ::ClipCursor(&Rect); • CView::OnLButtonDown(nFlags, point); • }
8.7 在视图中交互绘图 • 步骤6:按步骤五的方法向OnMouseMove()函数中添加对鼠标消息WM_MOUSEMOVE的处理,代码如下: • void CDrawView::OnMouseMove(UINT nFlags, CPoint point) • { • ::SetCursor(m_Cursor); • if(m_Drag) • { • CClientDC mydc(this); • mydc.SetROP2(R2_NOT); • mydc.MoveTo(m_StartPoint); • mydc.LineTo(m_OldPoint); • mydc.MoveTo(m_StartPoint); • mydc.LineTo(point); • m_OldPoint=point; • } • CView::OnMouseMove(nFlags, point); • }