返回 1
第 8章 图形图像处理
1.设备环境 ( DC) 的概念 。
2.常用的几个设备环境类如 CPaintDC,CClientDC、
CWindowDC和 CMetaFileDC类的主要特点及它们在使用方法上的区别 。
3.GDI的概念及常用的绘图设备类如 CGdiObject,CPen、
CBrush,Cfont和 CBitmap等的对象的创建和将其引入到设备环境中的方法 。
4.Windows下的坐标映像方式和特点以及如何设置坐标映像方式 。
5.几种常见的 Windows的坐标映像方式下的坐标转换方法 。
6.几种常见的基本图形元素如点,直线,矩形和文字等的绘制方式 。
返回 2
8.1 设备环境( DC)
( 1)在 Windows中,显示工作是基于设备环境的。所谓设备环境( DC)是一种 Windows数据结构,该结构包含应用程序设备输出时所需要的信息。
( 2) 在使用任何绘图函数之前必须建立一个设备环境对象 。
( 3) 在 Visual C++ 6.0的 MFC中提供了设备环境类 CDC,
它封装了绘图所需要的所有函数,其中包括了大多数的 Windows API中的 GDI函数。
返回 3
8.1.1 设备环境类
1,CDC类
( 1) CDC类是 CObject类的派生类,也是所有设备环境类的基类 。 CDC类定义了一个设备描述对象,并提供了对设备描述对象进行操作的成员函数以及对与窗口客户区有关的显示区进行操作的成员函数 。
( 2) CDC类提供的成员函数可以用于操作设备描述对象,使用绘图工具,选择图形设备界面,以及操作颜色和调色板,还用于取得和设置绘图属性,映射方式,
视图和窗口范围的操作,坐标的转换,区域的使用,
剪取,画线以及绘制图形和文字等操作 。
8.1 设备环境( DC)
返回 4
2,CPaintDC类
( 1) CPaintDC类是 CDC类的一个派生类,该类一般用在响应 WM_PAINT消息的函数 OnPaint()中 。
( 2) WM_PAINT消息是当窗口的某个区域需要重画时激发的窗口消息 。 当程序中的消息循环接到 WM_PAINT消息时 就 自动 调用 消息 处理 函 数 OnPaint(),如果在
OnPaint函数内定义了 CPaintDC类的对象,通过这个类对象就可以使用 CDC类的成员函数完成视图客户区中的图形绘制操作 。
8.1 设备环境( DC)
返回 5
3,CClientDC类
CClientDC类也是 CDC类的派生类 。 它只能在窗口的客户区 ( 即窗口中除了边框,标题栏,菜单栏以及状态栏外的中间部分 ) 中进行绘图,坐标点 ( 0,0) 通常指的是客户区的左上角 。 它的构造函数调用 GegDC函数,而析构函数调用 ReleaseDC函数 。
4,CWindowDC类
CWindowDC类也是 CDC类的派生类 。 其成员函数可以在窗口的客户区和非客户区 ( 即窗口的边框,标题栏,菜单栏以及状态栏 ) 中绘图,坐标点 ( 0,0) 是指整个屏幕的左上角 。 同 CClientDC类一样,它的构造函数调用
GegDC函数,而析构函数调用 ReleaseDC函数 。
8.1 设备环境( DC)
返回 6
5,CMdtaFileDC类
CMetaFileDC类提供了一个面向 Windows图元文件的设备环境,封装了在一个 Windows图元文件中绘图的方法 。
图元文件是一个与设备无关的图片的集合,由于它对图像的保存比像素更精确,因而往往在要求较高的场合下使用,例如 AutoCAD的图形保存等 。
8.1 设备环境( DC)
返回 7
8.1.2 几个设备环境类的主要差别
1,CWindowDC类与 CPaintDC,CClientDC类的区别其区别主要有以下两个方面:
( 1) 用 CPaintDC 和 CClientDC类的对象绘制图形时,绘制区只能在客户区,而不能在非客户区;而 CwindowDC
类既可以在窗口的客户区也可以在非客户区进行图形绘制 。
( 2) 在 CWindowDC绘图类下,坐标系是建立在整个屏幕上的,在像素坐标方式下,坐标原点在屏幕的左上角;而在 CPaintDC和 CClientDC绘图类下,坐标系是建立在客户区上的,在像素坐标方式下,坐标原点在客户区的左上角 。
8.1 设备环境( DC)
返回 8
2,CPaintDC类与 CClientDC类的区别
CPaintDC类的对象应用在 OnPaint函数中,以响应
Windows的 WM_PAINT消息;而 CClientDC类的对象应用在非响应消息 WM_PAINT的情况下 。
CPaintDC类响应 WM_PAINT消息,并自动完成绘制,这对维护图形的完整性有着重要的作用 。 CClientDC类可以实时地将图形绘制到屏幕上,不需要重画;而如果用 CPaintDC类的对象完成同样的工作,只能发出消息让屏幕上包含这条直线的区域重画,以把这条直线绘制到屏幕上 。
8.1 设备环境( DC)
返回 9
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.1 设备环境( DC)
返回 10
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对象从设备环境中分离出来 。
返回 11
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 绘图设备类返回 12
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 绘图设备类返回 13
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 绘图设备类返回 14
参数 nPenStyle用于设置画笔画线的线型其取值如下表:
线 型 风 格
PS_SOLID 创建一个实线画笔
PS_DASH 创建一个虚线画笔
PS_DOT 创建一个点线画笔
PS_DASHDOT 创建一个虚线和点线交替的画笔
PS_DASHDOTDOT 创建一个虚线和双点线交替的画笔
PS_NULL 创建一个空的画笔
PS_INSIDEFRAME 创建一个在封闭矩形框中使用的画笔
8.2 绘图设备类返回 15
注意:线型 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 绘图设备类返回 16
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 绘图设备类返回 17
8.2.3 CBrush类
CBrush类是 CGdiObject类的一个派生类,它封装了 Windows
图形设备界面 ( GDI) 中有关画刷的操作 。 CBrush类的用法与 CPen类似 。
8.2 绘图设备类返回 18
8.2.3.1 创建 CBrush对象利用 CBrush类的构造函数可创建 Cbrush对象 。
1,实心画刷用实心画刷进行图形填充时,以这种画刷的颜色实心填充 。 其创建方法如下:
( 1) 定义 CBrush对象,用函数 CreateSolidBrush对对象进行初始化 。
CBrush brush;
brush.CreateSolidBrush(RGB(255,0,0));
( 2) 定义 CBrush类对象,并利用构造函数对对象的参数进行初始化 。
CBrush brush(RGB(255,0,0));
( 3) 动态创建 。 用这种方法定义时,在操作完成后要删除创建的
CBrush对象 。
CBrush *brush;
Brush=new CBrush(RGB(255,0,0));
……
delete brush;
8.2 绘图设备类返回 19
2,影线画刷影线画刷不是用画刷的颜色实心填充图形,而是用不同的阴影图案来填充,填充方式如下表 。
影 线 风 格
HS_BDIACONAL 建立一个 45° 网格线的画刷 ( 从右向左 )
HS_CROSS 建立一个水平和垂直交叉网格线的画刷
HS_DIAGCROSS 建立一个两条 45° 垂直交叉网格线的画刷
HS_FDIAGONAL 建立一个 45° 网格线的画刷 ( 从左向右 )
HS_HORIZONTAL 建立一个水平网格线的画刷
HS_VERTICAL 建立一个垂直网格线的画刷
8.2 绘图设备类返回 20
影线画刷的创建方法同实心画刷一样:
( 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 绘图设备类返回 21
3,位图画刷位 图 画 刷 是 用 位 图 图 像 来 填 充 图 形 的 。 函数
CreatPatternBrush用来初始化一个位图画刷 。 以下代码创建一个位图画刷 ( 其中,pBitmap指向一个位图对象 ),
CBrush brush;
brush.CreatPatternBrush(pBitmap);
8.2 绘图设备类返回 22
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 绘图设备类返回 23
8.2.4 CFont类及创建 CFont类对象的方法
CFont类是 CGdiObject类的一个派生类,它封装了逻辑字体及方法。
8.2.4.1 创建 CFont对象
CFont类只有一个构造函数,在定义了一个 CFont类对象之后,必 须 用 成 员 函 数 CreateFont 或
CreateFontIndirect来初始化 CFont对象的参数 。
CreateFont函数的参数非常多,可查阅 MSDN。
8.2 绘图设备类返回 24
8.2.4.2在设备环境中选入字体下面介绍创建 CFont对象和 在 设备环境中 选入字体 的过程 。
void CDrawView::OnDraw(CDC * pDC)
{
Cfont font;
font.CreateFont(30,15,0,0,200,0,0,0,255,0,0,2,DEFA
ULT_PITCH,”VC”);
CFont* pOldFont= pDC->SelectObject(&font);
…… //省略进行文字绘制的部分
pDC->SelectObject(pOldFont);
}
8.2 绘图设备类返回 25
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.2 绘图设备类返回 26
在 Visual C++ 6.0中进行 Windows图形应用程序设计时,可以采用多种不同的坐标映射方式,即不同的坐标系 。
8.3.1 Windows映像方式及其设置方法
8.3.1.1 Windows映像方式
Windows映像方式就是 Windows下的逻辑坐标方式。一个实际物理屏幕是由像素组成的。
为了方便各种情况下的程序开发和减轻程序开发的负担,
Windows提供了几种映像方式,每一种映像方式提供不同的测量单位和坐标原点。详见下表:
8.3 坐标映射方式返回 27
映像方式 映像识别码 逻辑单位 X和 Y轴正向
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 坐标映射方式返回 28
8.3.1.2 Windows映像方式的设置方法在 MFC应用程序中,通过调用 CDC类的 SetMapMode()函数来设置映像方式 。 如:
pDC->SetMapMode(n);
其中,n是在上表中列出的映像方式的识别码 。
该函数的原型为:
virtual int SetMapMode( int nMapMode );
8.3 坐标映射方式返回 29
8.3.2 逻辑坐标和设备坐标的转换所谓设备坐标是针对屏幕或其他显示设备而言的 。 以屏幕为例,其原点在屏幕上的左上角; X轴的正方向向右;
Y轴的正方向向下;坐标单位为像素 。
而逻辑坐标是在内存中虚拟的一个坐标系,其原点在屏幕的左上角,X轴的正方向向右,Y轴的正方向向上,
其单位随着映像方式的不同而改变 。
8.3 坐标映射方式返回 30
8.3.2.1 设备无关性
Windows系统提供了坐标映像方式,并实现了设备无关性 。
所谓设备无关性指的是只要设定了映像方式,那么就会在不同的设备上显示出同样大小的图形 。
对于 MM_TEXT映像方式来说,因为其单位是像素且长度不固定 ( 即一个像素所占的实际长度随着设备的不同而不同 ),所以,在不同的显示和输出设备上不能保证其图形的大小一样 。
8.3 坐标映射方式返回 31
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.3 坐标映射方式返回 32
8.4 窗口和视口
8.4.1 窗口和视口的概念窗口指的是虚拟存在的一个屏幕,而视口指的是在屏幕上看到的视图客户区域 。 在 Windows中绘制图形时,
并不是把图形直接绘制到屏幕上,而是以各种映像方式下的逻辑坐标系将图形绘制到虚拟的窗口中,然后再将这个窗口中的内容映像到视口中 。 如果是映像到屏幕上就实现了图形的显示;如果是映像到打印机等输出设备上就实现了图形的打印输出 。
因此,窗口原点,视口原点和坐标系中的原点 3者的概念是不同的 。 窗口原点和视口原点指的是同一个点在窗口逻辑坐标和视口设备坐标系的坐标值,它决定了图形由窗口映射到视口时的相对位置 。
返回 33
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 窗口和视口返回 34
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 窗口和视口返回 35
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 窗口和视口返回 36
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 窗口和视口返回 37
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 窗口和视口返回 38
8.4.3.4 MM_ISOTROPIC和 MM_ANISOTROPIC映像方式的坐标转换在这两种映像方式下,映像后图形的大小要发生变化,
视口中的坐标也不再以像素为单位,而窗口中的逻辑坐标则是以像素为单位 。
在 MM_ISOTROPIC映像方式下,x和 y两方向同比例缩放,
而在 MM_ANISOTROPIC映像方式下,允许两方向不同比例放缩 。
8.4 窗口和视口返回 39
8.5 设置绘图模式绘图模式指定了画笔颜色和被填充物体内部颜色是如何与显示平面的颜色相混合的 。
绘图模式只能应用于光栅类设备,而不能用于矢量设备 。
设置绘图模式是利用 CDC类的成员函数 SetROP2来完成的,该函数的原型为:
int SetROP2( int nDrawMode );
其中:参数 nDrawMode表示新的绘图模式,该函数的返回值是原先的绘图模式 。 能够采用的绘图模式如下表 。
返回 40
绘图模式取值 含 义
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 像素颜色是既属于画笔颜色又属于屏幕颜色,但并不是两种颜色的公共部分的组合颜色的反色返回 41
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颜色值 。
返回 42
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 图形元素的绘制返回 43
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 图形元素的绘制返回 44
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 图形元素的绘制返回 45
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 图形元素的绘制返回 46
与文字的输出有关系的 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.6 图形元素的绘制返回 47
8.7 在视图中交互绘图本例的基本思想是:首先创建一个 SDI应用程序,当程序运行时,把鼠标指针移动到窗口客户区中,则鼠标光标的形状呈十字形,当按下鼠标左键并在视图窗口中拖动到另外一点时放开鼠标,则可以在按下鼠标的位置到放开鼠标时的位置间画一条直线。
步骤 1:启动 Visual C++ 6.0。
步骤 2:创建一个单文档的应用程序框架 。
步骤 3:在视图类中添加 4个成员变量,它们分别是:
m_Drag变量,是一个标志变量,用于表示目前用户是否正在拖动鼠标 。
m_Cursor变量,用于存放鼠标光标形状的句柄 。
m_StartPoint变量,用于记录当用户按鼠标左键时的光标所在位置的坐标 。
m_OldPoint变量,用于存放光标的当前位置 。
返回 48
步骤 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 在视图中交互绘图返回 49
步骤 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 在视图中交互绘图返回 50
步骤 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);
}
8.7 在视图中交互绘图返回 51
步骤 7:按步骤 5的方法向 OnMouseUp()函数中添加对鼠标消息 WM_LBUTTONUP
的处理,代码如下:
void CDrawView::OnLButtonUp(UINT nFlags,CPoint point)
{
if(m_Drag)
{
m_Drag=0;
::ReleaseCapture();
::ClipCursor(NULL);
CClientDC thedc(this);
thedc.SetROP2(R2_NOT);
thedc.MoveTo(m_StartPoint);
thedc.LineTo(m_OldPoint);
thedc.SetROP2(R2_COPYPEN);
thedc.MoveTo(m_StartPoint);
thedc.LineTo(point);
}
CView::OnLButtonUp(nFlags,point);
}
8.7 在视图中交互绘图返回 52
步骤 8:编译并运行此程序,可见,当鼠标在客户区中时,
鼠标光标呈十字形状,拖动鼠标可画直线 。
8.7 在视图中交互绘图返回 53
本章小结本章主要介绍了以下内容:
1,设备环境 ( DC) 的概念及常用的的几个设备环境类如
CPaintDC,CClientDC,CWindowDC和 CMetaFileDC类的主要特点及它们在使用方法上的区别 。
2,绘图设备类 ( GDI) 的概念及常用的绘图设备类如
CGdiObject,CPen,CBrush,Cfont和 CBitmap等的对象的创建和引入到设备环境中的方法 。
3,Windows下的坐标映像方式,设备方法及几种不同的坐标映像方式下的坐标转换方法 。
4,几种常见的基本图形元素如点,直线,矩形和文字等的绘制方式及相应的 CDC类的绘图函数 。
返回 54
第 8章 图形图像处理
1.设备环境 ( DC) 的概念 。
2.常用的几个设备环境类如 CPaintDC,CClientDC、
CWindowDC和 CMetaFileDC类的主要特点及它们在使用方法上的区别 。
3.GDI的概念及常用的绘图设备类如 CGdiObject,CPen、
CBrush,Cfont和 CBitmap等的对象的创建和将其引入到设备环境中的方法 。
4.Windows下的坐标映像方式和特点以及如何设置坐标映像方式 。
5.几种常见的 Windows的坐标映像方式下的坐标转换方法 。
6.几种常见的基本图形元素如点,直线,矩形和文字等的绘制方式 。
返回 2
8.1 设备环境( DC)
( 1)在 Windows中,显示工作是基于设备环境的。所谓设备环境( DC)是一种 Windows数据结构,该结构包含应用程序设备输出时所需要的信息。
( 2) 在使用任何绘图函数之前必须建立一个设备环境对象 。
( 3) 在 Visual C++ 6.0的 MFC中提供了设备环境类 CDC,
它封装了绘图所需要的所有函数,其中包括了大多数的 Windows API中的 GDI函数。
返回 3
8.1.1 设备环境类
1,CDC类
( 1) CDC类是 CObject类的派生类,也是所有设备环境类的基类 。 CDC类定义了一个设备描述对象,并提供了对设备描述对象进行操作的成员函数以及对与窗口客户区有关的显示区进行操作的成员函数 。
( 2) CDC类提供的成员函数可以用于操作设备描述对象,使用绘图工具,选择图形设备界面,以及操作颜色和调色板,还用于取得和设置绘图属性,映射方式,
视图和窗口范围的操作,坐标的转换,区域的使用,
剪取,画线以及绘制图形和文字等操作 。
8.1 设备环境( DC)
返回 4
2,CPaintDC类
( 1) CPaintDC类是 CDC类的一个派生类,该类一般用在响应 WM_PAINT消息的函数 OnPaint()中 。
( 2) WM_PAINT消息是当窗口的某个区域需要重画时激发的窗口消息 。 当程序中的消息循环接到 WM_PAINT消息时 就 自动 调用 消息 处理 函 数 OnPaint(),如果在
OnPaint函数内定义了 CPaintDC类的对象,通过这个类对象就可以使用 CDC类的成员函数完成视图客户区中的图形绘制操作 。
8.1 设备环境( DC)
返回 5
3,CClientDC类
CClientDC类也是 CDC类的派生类 。 它只能在窗口的客户区 ( 即窗口中除了边框,标题栏,菜单栏以及状态栏外的中间部分 ) 中进行绘图,坐标点 ( 0,0) 通常指的是客户区的左上角 。 它的构造函数调用 GegDC函数,而析构函数调用 ReleaseDC函数 。
4,CWindowDC类
CWindowDC类也是 CDC类的派生类 。 其成员函数可以在窗口的客户区和非客户区 ( 即窗口的边框,标题栏,菜单栏以及状态栏 ) 中绘图,坐标点 ( 0,0) 是指整个屏幕的左上角 。 同 CClientDC类一样,它的构造函数调用
GegDC函数,而析构函数调用 ReleaseDC函数 。
8.1 设备环境( DC)
返回 6
5,CMdtaFileDC类
CMetaFileDC类提供了一个面向 Windows图元文件的设备环境,封装了在一个 Windows图元文件中绘图的方法 。
图元文件是一个与设备无关的图片的集合,由于它对图像的保存比像素更精确,因而往往在要求较高的场合下使用,例如 AutoCAD的图形保存等 。
8.1 设备环境( DC)
返回 7
8.1.2 几个设备环境类的主要差别
1,CWindowDC类与 CPaintDC,CClientDC类的区别其区别主要有以下两个方面:
( 1) 用 CPaintDC 和 CClientDC类的对象绘制图形时,绘制区只能在客户区,而不能在非客户区;而 CwindowDC
类既可以在窗口的客户区也可以在非客户区进行图形绘制 。
( 2) 在 CWindowDC绘图类下,坐标系是建立在整个屏幕上的,在像素坐标方式下,坐标原点在屏幕的左上角;而在 CPaintDC和 CClientDC绘图类下,坐标系是建立在客户区上的,在像素坐标方式下,坐标原点在客户区的左上角 。
8.1 设备环境( DC)
返回 8
2,CPaintDC类与 CClientDC类的区别
CPaintDC类的对象应用在 OnPaint函数中,以响应
Windows的 WM_PAINT消息;而 CClientDC类的对象应用在非响应消息 WM_PAINT的情况下 。
CPaintDC类响应 WM_PAINT消息,并自动完成绘制,这对维护图形的完整性有着重要的作用 。 CClientDC类可以实时地将图形绘制到屏幕上,不需要重画;而如果用 CPaintDC类的对象完成同样的工作,只能发出消息让屏幕上包含这条直线的区域重画,以把这条直线绘制到屏幕上 。
8.1 设备环境( DC)
返回 9
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.1 设备环境( DC)
返回 10
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对象从设备环境中分离出来 。
返回 11
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 绘图设备类返回 12
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 绘图设备类返回 13
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 绘图设备类返回 14
参数 nPenStyle用于设置画笔画线的线型其取值如下表:
线 型 风 格
PS_SOLID 创建一个实线画笔
PS_DASH 创建一个虚线画笔
PS_DOT 创建一个点线画笔
PS_DASHDOT 创建一个虚线和点线交替的画笔
PS_DASHDOTDOT 创建一个虚线和双点线交替的画笔
PS_NULL 创建一个空的画笔
PS_INSIDEFRAME 创建一个在封闭矩形框中使用的画笔
8.2 绘图设备类返回 15
注意:线型 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 绘图设备类返回 16
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 绘图设备类返回 17
8.2.3 CBrush类
CBrush类是 CGdiObject类的一个派生类,它封装了 Windows
图形设备界面 ( GDI) 中有关画刷的操作 。 CBrush类的用法与 CPen类似 。
8.2 绘图设备类返回 18
8.2.3.1 创建 CBrush对象利用 CBrush类的构造函数可创建 Cbrush对象 。
1,实心画刷用实心画刷进行图形填充时,以这种画刷的颜色实心填充 。 其创建方法如下:
( 1) 定义 CBrush对象,用函数 CreateSolidBrush对对象进行初始化 。
CBrush brush;
brush.CreateSolidBrush(RGB(255,0,0));
( 2) 定义 CBrush类对象,并利用构造函数对对象的参数进行初始化 。
CBrush brush(RGB(255,0,0));
( 3) 动态创建 。 用这种方法定义时,在操作完成后要删除创建的
CBrush对象 。
CBrush *brush;
Brush=new CBrush(RGB(255,0,0));
……
delete brush;
8.2 绘图设备类返回 19
2,影线画刷影线画刷不是用画刷的颜色实心填充图形,而是用不同的阴影图案来填充,填充方式如下表 。
影 线 风 格
HS_BDIACONAL 建立一个 45° 网格线的画刷 ( 从右向左 )
HS_CROSS 建立一个水平和垂直交叉网格线的画刷
HS_DIAGCROSS 建立一个两条 45° 垂直交叉网格线的画刷
HS_FDIAGONAL 建立一个 45° 网格线的画刷 ( 从左向右 )
HS_HORIZONTAL 建立一个水平网格线的画刷
HS_VERTICAL 建立一个垂直网格线的画刷
8.2 绘图设备类返回 20
影线画刷的创建方法同实心画刷一样:
( 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 绘图设备类返回 21
3,位图画刷位 图 画 刷 是 用 位 图 图 像 来 填 充 图 形 的 。 函数
CreatPatternBrush用来初始化一个位图画刷 。 以下代码创建一个位图画刷 ( 其中,pBitmap指向一个位图对象 ),
CBrush brush;
brush.CreatPatternBrush(pBitmap);
8.2 绘图设备类返回 22
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 绘图设备类返回 23
8.2.4 CFont类及创建 CFont类对象的方法
CFont类是 CGdiObject类的一个派生类,它封装了逻辑字体及方法。
8.2.4.1 创建 CFont对象
CFont类只有一个构造函数,在定义了一个 CFont类对象之后,必 须 用 成 员 函 数 CreateFont 或
CreateFontIndirect来初始化 CFont对象的参数 。
CreateFont函数的参数非常多,可查阅 MSDN。
8.2 绘图设备类返回 24
8.2.4.2在设备环境中选入字体下面介绍创建 CFont对象和 在 设备环境中 选入字体 的过程 。
void CDrawView::OnDraw(CDC * pDC)
{
Cfont font;
font.CreateFont(30,15,0,0,200,0,0,0,255,0,0,2,DEFA
ULT_PITCH,”VC”);
CFont* pOldFont= pDC->SelectObject(&font);
…… //省略进行文字绘制的部分
pDC->SelectObject(pOldFont);
}
8.2 绘图设备类返回 25
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.2 绘图设备类返回 26
在 Visual C++ 6.0中进行 Windows图形应用程序设计时,可以采用多种不同的坐标映射方式,即不同的坐标系 。
8.3.1 Windows映像方式及其设置方法
8.3.1.1 Windows映像方式
Windows映像方式就是 Windows下的逻辑坐标方式。一个实际物理屏幕是由像素组成的。
为了方便各种情况下的程序开发和减轻程序开发的负担,
Windows提供了几种映像方式,每一种映像方式提供不同的测量单位和坐标原点。详见下表:
8.3 坐标映射方式返回 27
映像方式 映像识别码 逻辑单位 X和 Y轴正向
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 坐标映射方式返回 28
8.3.1.2 Windows映像方式的设置方法在 MFC应用程序中,通过调用 CDC类的 SetMapMode()函数来设置映像方式 。 如:
pDC->SetMapMode(n);
其中,n是在上表中列出的映像方式的识别码 。
该函数的原型为:
virtual int SetMapMode( int nMapMode );
8.3 坐标映射方式返回 29
8.3.2 逻辑坐标和设备坐标的转换所谓设备坐标是针对屏幕或其他显示设备而言的 。 以屏幕为例,其原点在屏幕上的左上角; X轴的正方向向右;
Y轴的正方向向下;坐标单位为像素 。
而逻辑坐标是在内存中虚拟的一个坐标系,其原点在屏幕的左上角,X轴的正方向向右,Y轴的正方向向上,
其单位随着映像方式的不同而改变 。
8.3 坐标映射方式返回 30
8.3.2.1 设备无关性
Windows系统提供了坐标映像方式,并实现了设备无关性 。
所谓设备无关性指的是只要设定了映像方式,那么就会在不同的设备上显示出同样大小的图形 。
对于 MM_TEXT映像方式来说,因为其单位是像素且长度不固定 ( 即一个像素所占的实际长度随着设备的不同而不同 ),所以,在不同的显示和输出设备上不能保证其图形的大小一样 。
8.3 坐标映射方式返回 31
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.3 坐标映射方式返回 32
8.4 窗口和视口
8.4.1 窗口和视口的概念窗口指的是虚拟存在的一个屏幕,而视口指的是在屏幕上看到的视图客户区域 。 在 Windows中绘制图形时,
并不是把图形直接绘制到屏幕上,而是以各种映像方式下的逻辑坐标系将图形绘制到虚拟的窗口中,然后再将这个窗口中的内容映像到视口中 。 如果是映像到屏幕上就实现了图形的显示;如果是映像到打印机等输出设备上就实现了图形的打印输出 。
因此,窗口原点,视口原点和坐标系中的原点 3者的概念是不同的 。 窗口原点和视口原点指的是同一个点在窗口逻辑坐标和视口设备坐标系的坐标值,它决定了图形由窗口映射到视口时的相对位置 。
返回 33
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 窗口和视口返回 34
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 窗口和视口返回 35
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 窗口和视口返回 36
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 窗口和视口返回 37
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 窗口和视口返回 38
8.4.3.4 MM_ISOTROPIC和 MM_ANISOTROPIC映像方式的坐标转换在这两种映像方式下,映像后图形的大小要发生变化,
视口中的坐标也不再以像素为单位,而窗口中的逻辑坐标则是以像素为单位 。
在 MM_ISOTROPIC映像方式下,x和 y两方向同比例缩放,
而在 MM_ANISOTROPIC映像方式下,允许两方向不同比例放缩 。
8.4 窗口和视口返回 39
8.5 设置绘图模式绘图模式指定了画笔颜色和被填充物体内部颜色是如何与显示平面的颜色相混合的 。
绘图模式只能应用于光栅类设备,而不能用于矢量设备 。
设置绘图模式是利用 CDC类的成员函数 SetROP2来完成的,该函数的原型为:
int SetROP2( int nDrawMode );
其中:参数 nDrawMode表示新的绘图模式,该函数的返回值是原先的绘图模式 。 能够采用的绘图模式如下表 。
返回 40
绘图模式取值 含 义
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 像素颜色是既属于画笔颜色又属于屏幕颜色,但并不是两种颜色的公共部分的组合颜色的反色返回 41
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颜色值 。
返回 42
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 图形元素的绘制返回 43
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 图形元素的绘制返回 44
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 图形元素的绘制返回 45
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 图形元素的绘制返回 46
与文字的输出有关系的 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.6 图形元素的绘制返回 47
8.7 在视图中交互绘图本例的基本思想是:首先创建一个 SDI应用程序,当程序运行时,把鼠标指针移动到窗口客户区中,则鼠标光标的形状呈十字形,当按下鼠标左键并在视图窗口中拖动到另外一点时放开鼠标,则可以在按下鼠标的位置到放开鼠标时的位置间画一条直线。
步骤 1:启动 Visual C++ 6.0。
步骤 2:创建一个单文档的应用程序框架 。
步骤 3:在视图类中添加 4个成员变量,它们分别是:
m_Drag变量,是一个标志变量,用于表示目前用户是否正在拖动鼠标 。
m_Cursor变量,用于存放鼠标光标形状的句柄 。
m_StartPoint变量,用于记录当用户按鼠标左键时的光标所在位置的坐标 。
m_OldPoint变量,用于存放光标的当前位置 。
返回 48
步骤 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 在视图中交互绘图返回 49
步骤 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 在视图中交互绘图返回 50
步骤 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);
}
8.7 在视图中交互绘图返回 51
步骤 7:按步骤 5的方法向 OnMouseUp()函数中添加对鼠标消息 WM_LBUTTONUP
的处理,代码如下:
void CDrawView::OnLButtonUp(UINT nFlags,CPoint point)
{
if(m_Drag)
{
m_Drag=0;
::ReleaseCapture();
::ClipCursor(NULL);
CClientDC thedc(this);
thedc.SetROP2(R2_NOT);
thedc.MoveTo(m_StartPoint);
thedc.LineTo(m_OldPoint);
thedc.SetROP2(R2_COPYPEN);
thedc.MoveTo(m_StartPoint);
thedc.LineTo(point);
}
CView::OnLButtonUp(nFlags,point);
}
8.7 在视图中交互绘图返回 52
步骤 8:编译并运行此程序,可见,当鼠标在客户区中时,
鼠标光标呈十字形状,拖动鼠标可画直线 。
8.7 在视图中交互绘图返回 53
本章小结本章主要介绍了以下内容:
1,设备环境 ( DC) 的概念及常用的的几个设备环境类如
CPaintDC,CClientDC,CWindowDC和 CMetaFileDC类的主要特点及它们在使用方法上的区别 。
2,绘图设备类 ( GDI) 的概念及常用的绘图设备类如
CGdiObject,CPen,CBrush,Cfont和 CBitmap等的对象的创建和引入到设备环境中的方法 。
3,Windows下的坐标映像方式,设备方法及几种不同的坐标映像方式下的坐标转换方法 。
4,几种常见的基本图形元素如点,直线,矩形和文字等的绘制方式及相应的 CDC类的绘图函数 。
返回 54