您的位置:首页 > 编程语言 > C语言/C++

《VC++深入详解》学习笔记 第十一章 图形的保存和重绘

2012-09-11 20:42 344 查看
1.坐标空间和转换

(1)坐标空间:Win32应用程序编程接口(API)使用四种坐标空间:世界坐标系空间、页面空间、设备空间和物理设备空间,应用程序运用世界坐标系空间对图形输出进行旋转、斜切或者反射,Win32
API把世界坐标系空间和页面空间称为逻辑空间,物理设备空间通常是指应用程序的客户区,但它也包括整个桌面、完整的窗口等

(2)转换:把对象从一个坐标空间按复制到另一个坐标空间时改变或转变这一对象的大小、方向和形态

在实际绘图时,世界坐标系空间中的一个区域要先被映射到页面空间,然后由页面空间映射到设备空间,设备空间通常它的左上角时(0,0)点,然后再由设备空间映射到物理设备空间(通常就是屏幕)于是图形就在屏幕上显示出来了

(3)设备环境属性:窗口原点、视口原点、窗口范围、视口范围,其中窗口基于逻辑坐标的(像素、毫米、英寸等为单位),视口基于设备坐标的(像素),通常视口与客户区相同

页面空间到设备空间的转换所用的是两个矩形的宽与高的比率,其中页面空间中的矩形被称为窗口,设备空间中的矩形被称为视口,Windows把窗口原点映射到视口原点,把窗口范围映射到视口范围,就完成了这种装换

(4)设备空间到物理空间的转换只限于平移,并由Windows窗口管理部分控制

(5)SetWorldTransform函数:世界坐标空间

(6)逻辑坐标和设备坐标间相互转换

2.图形的保存和重绘

(1)将图形保存起来,在OnDraw函数中完成图形的输出

(2)新建一个类,定义成员变量,保存图形的类型、起点、终点

(3)在CGraphicView中构建一个容器(CPtrArray)存放新建的类的对象指针,每画一个图形新建一个对象存放图形的信息(不要用局部对象,要在堆上分配,最后释放)

(4)在OnDraw函数中将对象中保存的图形输出

3.OnPaint与OnDraw

(1)窗口重绘时会发送一个WM_PAINT消息,它的响应函数是OnPaint,CWiew类在OnPaint的实现中调用OnDraw函数,所以在OnDraw函数中画的图形能一直显示

void CView::OnPaint()

{

CPaintDC dc(this);

OnPrepareDC(&dc);

OnDraw(&dc);

}

1.OnPaint函数首先利用CPaintDC类构造一个设备上下文对象:dc;响应WM_PAINT消息时要获得句柄只能用BeginPaint函数,在CPaintDC类的构造函数和析构函数中调用了BeginPaint函数和EndPaint函数。在程序的其他地方想要获得DC句柄只能用GetDC和ReleaseDC函数

2.接着,调用了OnPrepareDC函数,这时一个虚函数,如果因屏幕被调用,默认实现是什么都不做,要重写这个函数,要在该函数的开始处调用基类的OnPrepareDC函数

3.接着,调用OnDraw函数,这也是一个虚函数。

4.如果我们在程序中捕获WM_PAINT消息自己重写OnPaint消息,则系统不再调用OnDraw函数,当然我们也可以在自己的函数中模仿系统的OnPaint函数,调用OnDraw并在这之前调用OnPrepareDC函数。

4.窗口滚动功能的实现

(1)CScrollView类

(2)创建MFC程序时将视类的基类选为CScrollView类,视类就有了窗口滚动的能力

(3)对滚动窗口,在初始创建,要进行一些设置:CScrollView类的成员函数SetScrollSize

函数原型:void SetScrollSizes(int nMapMode,SIZE sizeTotal,

const SIZE& sizePage = sizeDefault,const SIZE& sizeLine = sizeDefault);

// nMapMode指定映射模式 sizeTotal设置滚动视图窗口总的尺寸

// sizePage设置响应鼠标单击滚动条时水平和垂直方向滚动的量

// sizeLine设置响应鼠标单击滚动箭头时水平和垂直方向滚动的量

在视类窗口创建之后再调用SetScrollSize函数,这里可以为CGraphic View类重载一个虚函数:OnInitialUpdate,该函数是在窗口完全创建完成后第一个调用的函数,在该函数中调用SetScrollSize函数

以CScrollView类为基类创建的窗口,系统已经自动完成这些内容

(4)图形错位现象

1.拖动滚动条,图形显示的位置会出错,因为GDI函数使用的是逻辑坐标而Windows需要将其装换为设备坐标,然后输出图形;调用OnDraw函数之前,OnPaint函数调用了OnPrepareDC函数来调整显示上下文的属性。拖动窗口后视口原点的改变(窗口原点没有变化)导致图形错位

2.不管视口原点和窗口原点如何变化设备坐标(0,0)始终是窗口客户区左上角

3.解决办法:在保存坐标点之前,调用OnPrepareDC函数,调整显示上下文的属性

OnPrepareDC(&dc);

dc.DPtoLP(&m_ptOrigin);

dc.DPtoLP(&point);

4.每次窗口重绘时,都会调用OnPrepareDC函数,而OnPrepareDC会随时根据滚动窗口的位置来调整视口的原点,也就是说,视口的原点是不断变化的,要相应的进行逻辑坐标和设备坐标的转换

5.元文件:一种保存图形和重绘图形的方式

(1)元文件设备上下文类:CMetaFileDC(派生于CDC类),一个元文件DC包含了一系列图形设备接口命令,在程序中可以重写这些命令,以便创建所需要的图形或文本。元文件就像一块画布,在画布上画的图形可以随时展示(元文件画的图形在播放之前是看不到的,实际上是在内存中画的)。元文件并没有包含所绘制图形的图形数据,它包含的是图形的绘制命令。

(2)利用CMetaFileDC构造函数构造一个元文件DC对象,然后调用该类的Create成员函数创建一个Windows元文件设备上下文,并将其与已构造的CMetaFileDC对象关联起来

函数原型:BOOL Create(LPCTSTR lpszFilename = NULL);//参数指定要创建的元文件的文件名

//若为NULL,则创建的元文件是一个内存元文件

(3)给已创建的元文件DC对象发送一系列的GDI命令,例如MoveTo

(4)给元文件DC对象发送需要的命令后,调用Close成员函数关闭元文件设备上下文,返回元文件句柄(HMETAFILR类型)

(5)以得到的元文件句柄为参数,利用CDC类的PlayMetaFile成员函数播放该元文件

函数原型:BOOL PlayMetaFile(HMETAFILE hMF);

(6)播放完其中的图形绘制命令之后,就不再需要该元文件,源文件也是一种资源,使用结束后要释放:DeleteMetaFile

函数原型:BOOL DeleteMetaFile(HMETAFILE hmf);

(7)HMETAFILE hmetaFile;

hmetaFile = dcMetaFile.Close();

pDC->playMetaFile(hmetaFile);

m_dcMetaFile.Create();

m_dcMetaFile.PlayMetaFile(hmetaFile)//保存先前绘制的图形,用新建的元文件DC(m_dcMetaFile)播放先前的元文件,它会将先前的图形在该元文件中绘制,这样新的元文件就保存了先前所画的所有图形,还可以增加自己独有的图形

DeleteMetaFile(hmetaFile);

(8)元文件的保存和打开

若我们把元文件保存为磁盘文件,以后需要时可以随时打开该文件

1.为了保存元文件,可以使用CopyMetaFile函数,该函数的作用是把Windows元文件的内容复制到指定的文件

函数原型:HMETAFILE CopyMetaFile(HMETAFILE hmfSrc,LPCTSTR lpszFile);

//第一个参数指定要赋值的Windows元文件的句柄,第二个参数指定赋值目标文件的名称

HMETAFILE hmetaFile;

hmetaFile = dcMetaFile.Close();

CopyMetaFile(hmetaFile,”meta.wmf”);//元文件扩展名通常为wmf(Window
Meta File)

m_dcMetaFile.Create();//复制完成后,需要在创建一个元文件DC,以备下一次绘图使用

DeleteMetaFile(hmetaFile);

2.打开元文件:利用GetMetaFile函数得到指定元文件的句柄(Win32API中已经废弃了这个函数,Win32应用程序应该使用GetEnhMetaFile函数创建一个增强型元文件句柄)

HMETAFILE hmetaFile;

hmetaFile = GetMetaFile(”meta.wmf”);

m_dcMetaFile.PlayMetaFile(hmetaFile);

DeleteMetaFile(hmetaFile);

Invalidate();

6.兼容设备描述表:一种保存图形和重绘图形的方式

(1)为CGraphicView类创建一个兼容DC对象

(2)利用兼容DC实现图形的保存

(3)在兼容DC初始创建时,它会选择一幅单色位图,之前我们用SelectObject函数将一幅位图选入兼容DC来确定其显示表面的大小,现在我们需要去创建一个与当前窗口DC相兼容的DC,它的表面大小与当前客户区一致,可以利用兼容位图来实现,CBitmap的成员函数:CreateCompatibleBitmap可以通过指定的宽和高创建一幅与指定DC相兼容的位图。

(4)有了兼容位图后,可以把兼容位图选入兼容DC,确定兼容DC显示表面的大小

(5)兼容DC实际上是一块内存,利用它绘制的图形在窗口中是看不到的,因此要在视类的OnDraw函数中利用已创建的兼容DC对象,将该DC的内容复制到目的DC中,从而实现图形的显示。

CRect rect;

GetClientRect(&rect);

pDC->BitBlt(0,0,rect.Width(),rect.Height(),&m_dcCompatible,0,0,SRCCOPY);

(6)程序运行出现问题,因为CreateCompatibleBitmap函数返回的位图对象只包含相应设备描述表中的位图的位图信息头,并不包含该位图的颜色表和像素数据块,所以选入该位图对象的设备描述表不能像选入普通位图对象的设备描述表一样应用,必须在SelectObject函数之后调用BitBlt函数将原始设备描述表的颜色表及像素数据块复制到兼容设备描述表

m_dcCompatible.BitBlt(0,0,rect.Width(),rect.Height(),&dc,0,0,SRCCOPY);

(7)需要记住:在调用SelectObject操作将兼容位图选入兼容DC之后,还需要调用BitBlt函数将原始设备描述表的颜色表及像素数据块复制到兼容设备描述表
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: