【转】第十一章 图形保存和重绘

阅读本文前,我们假设您已经:
         1,知道如何创建一个单文档的App Wizard
         2,知道C++ 类、函数重载等简单知识
         3,知道如何给View类或者Doc文档添加成员变量
         4,会用MFC的IDE调试工具最好,那么本文的程序您可以copy去调试 
         5,知道如何为某个框架类添加虚函数或消息处理函数
  
 

1,透明画刷

CClientDC dc(this);

CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));

dc.SelectObject(pBrush);

2,保存绘制的图像(窗口重绘时仍然存在)

CGraphView类中添加m_ptOrigin,m_ptEnd,m_nDrawType三个变量,分别用于保存图像起始点、终止点和图像类型

1)构造一个CGraph类,用于存放每个对象

头文件Graph.h

#if !defined(AFX_GRAPH_H__)

#define AFX_GRAPH_H__

 

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

 

class CGraph 

{

public:

         UINT m_nDrawType;

         CPoint m_ptOrigin;

         CPoint m_ptEnd;

         CGraph();

         CGraph(   UINT m_nDrawType,CPoint m_ptOrigin,CPoint m_ptEnd);

         virtual ~CGraph();

 

};

2),因为不知道将会绘制多少图像对象,用集合类来替代复杂的链表结构。View类中定义,添加

 CPtrArray m_ptArray;

3),OnLButtonDownOnLButtonUp中分别保存两个点,并在OnLButtonUp中添加以下语句,用集合类来保存图像元素

//CGraph graph(m_nDrawType,m_ptOrigin,m_ptEnd);这种方法是错误的,因为局部变量将被销毁

CGraph *pGraph;

pGraph = new CGraph(m_nDrawType,m_ptOrigin,m_ptEnd);//在堆中分配内存,不会被释放,生命周期和进程一致,直至delete出现

m_ptArray.Add(&graph);

 

CPaintDC只能在WM_PAINT的消息相应中使用,其创建和析构调用BenginDCEndDC

CClientDC创建时调用GetDC,析构时调用ReleaseDC

OnPrepareDC,CScrollView调用OnPrepareDC会做调整,

OnPaint()函数为WM_PAINT的相应函数,如果没有重载OnPaint函数,那么OnPaint基函数是直接调用OnDraw函数。如果重载了OnPaint()函数,那么只有在子类中OnPaint()的调用OnDraw()

 

Win32应用程序接口(API)使用四种坐标空间:世界坐标系空间、页面空间、设备空间、和物理设备空间。应用程序运用世界坐标系空间对图形输出进行旋转、斜切(扭曲)或者反射

Win32 API把世界坐标系空间和页面空间成为逻辑空间;作后一种坐标空间(物理设备空间)通常指应用程序窗口的客户区;但是它也包括整个桌面、完整的窗口(包括框架、标题栏和菜单栏)或打印机的一页或绘图仪的一页纸。物理设备的尺寸随显示器、打印机或绘图仪所设置的尺寸而变化。

如果要在物理设备上绘制输出,windows把一个矩形区域从一个坐标空间拷贝到(映射到)另一个坐标空间,直至最终完整地输出呈现在物理设备上(通常是屏幕或者打印机)

如果该应用程序调用了SetWorldTransform函数,那么映射就从应用程序的世界坐标系空间开始;否则,映射在页面控件中进行。在Windows把矩形区域的每一点从一个空间拷贝到另一个空间时,它采用了一种被称为转换的算法,转换是把对象从一个坐标空间拷贝到另一个坐标空间时改变(转变)这一对象的刀削、方位、和形态,尽管转换把对象看成一个整体,但它也作用于对象中的每一点或每条线。

一个典型转换的例子

图形旋转、斜切的例子在MSDNusing Coordinate spaces and transformations中有TransformAndDraw函数的实现,可以仿照之。例如AutoCAD中对图像的切割、旋转、局部放大等。

OnInitialUpdate,窗口创建完成后,第一个被调用的函数

SetMapMode函数

SetScrollSizes在窗口创建之后调用

滚动窗口中重绘图像时出现的图形移动问题

1,原因:重绘时调用了OnPrepareDC设置了视点坐标

2,保存数据时先调用OnPrepareDC调整,再调用DPtoLP转换后,再保存,就可以了。

 

另外两种保存图形数据的方法

CMetaFileDC

1,在View.h中添加定义

CMetaFileDC m_dcMetaFile;

2,在view的构造函数中初始化

m_dcMetaFile.Create();

3,OnLButtonUp中将所有dc指针更换为m_dcMetaFile

4,在OnDraw中以前的绘图语句注释掉,添加以下

HMETAFILE hmetaFile;

hmetaFile=m_dcMetaFile.Close();

pDC->PlayMetaFile(hmetaFile);//播放原文件

m_dcMetaFile.Create();//新创建原文件,准备原文件设备上下文

m_dcMetaFile.PlayMetaFile(hmetaFile);//把前面的原文件播放一遍,避免丢失。相当于保存以前的绘图命令

DeleteMetaFile(hmetaFile);//播放结束,释放原文件句柄

5,保存

copyMetaFile

1)保存语句

HMETAFILE hmetaFile;

hmetaFile=m_dcMetaFile.Close();

CopyMetaFile(hmetaFile,"meta.wmf");

m_dcMetaFile.Create();

DeleteMetaFile(hmetaFile);

2)打开图形

HMETAFILE hmetaFile;

hmetaFile=GetMetaFile("meta.wmf");

m_dcMetaFile.PlayMetaFile(hmetaFile);

DeleteMetaFile(hmetaFile);

Invalidate();

 

利用兼容DC保存图形

1,在View中定义变量

CDC m_dcCompatible;

2,OnLButtonUp中添加

if(!m_dcCompatible.m_hDC)

{

m_dcCompatible.CreateCompatibleDC(&dc);

CRect rect;

GetClientRect(&rect);

CBitmap bitmap;

//用当前客户区大小来创建兼容位图

bitmap.CreateCompatibleBitmap(&dc,rect.Width(),rect.Height());

//把兼容位图选入兼容DC中。此位图bitmap可以是普通位图,也可以是兼容位图

m_dcCompatible.SelectObject(&bitmap);

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

m_dcCompatible.SelectObject(pBrush);

}

3,把OnLButtonUpdc指针都换成m_dcCompatible

已经建立好的基类为CView的视类,改变为有滚动条的视类,即CScroolView步骤

1,CXXXView.h and .cpp文件中CView统统用CScrollView替换,注意类定义继承的地方

2,添加OnInitialUpdate,在其中添加滚动条的初始化。不做这一步的话,将运行出错

SetScrollSizes(MM_TEXT,CSize(800,600));

    欢迎以任何形式转载本文,只要对您有用
    欢迎给我来信 webbery (at) sohu (dot) com (分别用@,.替换at,dot)

    韦伯主页: http://mail.ustc.edu.cn/~bywang(提供此笔记系列相关源程序下载)
    韦伯Blog: http://webbery.tianyablog.com
参考书目和网站: 
    (1)孙鑫VC++视频
    (2)1-6章主要参考: hbyufan的BLog
    (3)11-20章主要参考: songpeng的Blog

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值