设为首页 加入收藏

TOP

vc++笔记之绘图程序 (三)
2014-11-23 19:22:48 】 浏览:893
Tags:笔记 绘图 程序
urn TRUE;

}

文档的清理

在关闭文档的最后一个子窗口时,框架要求文档清理数据。文档清理在文档类的DeleteContents()中完成。同样需要用ClassWizard生成DeleteContents的框架。

void CDrawDoc::DeleteContents()

{

// TODO: Add your specialized code here and/or call the base class

 

while (!m_strokeList.IsEmpty())

{

delete m_strokeList.RemoveHead();

}

CDocument::DeleteContents();

}

DeleteContents()从头到尾遍里链表中的所有对象指针,并通过指针删除对象,然后用RemoveHead()删除该指针。

文档的串行化

现在设计文档的Serialize函数,实现文档数据的保存和载入:

void CDrawDoc::Serialize(CArchive& ar)

{

if (ar.IsStoring())

{

 

ar << m_sizeDoc;

}

else

{

 

ar >> m_sizeDoc;

}

 

m_strokeList.Serialize(ar);

}

文档的Serialize()函数首先分别保存和载入文档大小,然后调用m_strokeList的Serialize()方法。m_strokeList.Serialize()又会自动调用存放在m_strokeList中的每一个元素CStroke的串行化方法CStroke.Serialize()最终实现文档的串行化即文档所包含的对象的存储和载入。

在DrawDoc.cpp的末尾加上CStroke::Serialize()函数的定义:

void CStroke::Serialize(CArchive& ar)

{

if (ar.IsStoring())

{

ar << m_rectBounding;

ar << (WORD)m_nPenWidth;

m_pointArray.Serialize(ar);

}

else

{

ar >> m_rectBounding;

WORD w;

ar >> w;

m_nPenWidth = w;

m_pointArray.Serialize(ar);

}

}

CStroke的Serialize()依次保存(载入)笔划的矩形边界、线宽度以及点数组。注意m_nPenWidth是UINT类型的,>>和<<操作符并不支持UINT类型但却支持WORD,因此要作UINT和DWORD之间的类型转换。点数组的串行化通过调用数组的每个CPoint类元素的Serialize()完成,CPoint类是MFC类,它本身支持串行化。

8.3.3 设计绘图程序的视图类

视图类数据成员

现在着手设计绘图程序的视图类。首先,需要在视图中增加两个数据成员:

class CDrawView : public CScrollView

{

protected: // create from serialization only

CDrawView();

DECLARE_DYNCREATE(CDrawView)

// Attributes

public:

CDrawDoc* GetDocument();

 

protected:

CStroke* m_pStrokeCur; // the stroke in progress

CPoint m_ptPrev; // the last mouse pt in the stroke in progress

// 其它数据成员和成员函数......

};

m_pStrokeCur代表正在画的那一个笔划。m_ptPrev保存鼠标上次移动位置。画图时,LineTo从这个点到当前鼠标位置画一条直线。

视图初始化

接下去,要初始化视图。由于是卷滚视图,因此要在OnInitialUpdate()中设置卷滚范围。在用户选择File->New菜单或File->Open菜单时,框架调用OnInitialUpdate函数。

void CDrawView::OnInitialUpdate()

{

 

SetScrollSizes(MM_LOENGLISH, GetDocument()->GetDocSize());

CScrollView::OnInitialUpdate();

}

注意我们这里将映射模式设置为MM_LOENGLISH,MM_LOENGLISH以0.01英寸为逻辑单位,y轴方向向上递增,同MM_TEXT的y轴递增方向相反。

视图绘制

在CDrawView::OnDraw()内完成视图绘制工作。在以前的文档视结构程序中,在需要绘图的时侯都是绘制整个窗口。如果窗口只有很小的一部分被覆盖,是否可以只绘制那些需要重画的部分?

回答是肯定的,而且大部分程序都这么做了。

比如,象下图这种情况:

 

图8-5 窗口的重绘

当窗口2从窗口1上移开后,只需要重画阴影线所包围的区域就够了。

当Windows通知窗口要重绘用户区时,并非整个用户区都需要重绘,需要重绘的区域称为“无效矩形区”,如上图中的阴影区域。用户区中出现一个无效矩形提示Windows在应用程序队列中放置WM_PAINT消息。由于WM_PAINT消息优先级最低,可调用UpdateWindows直接立即向窗口发送WM_PAINT消息,从而立即重绘。无效矩形区限制程序只能在该区域中绘图,越界的绘图将被裁剪掉。下面三个函数与无效矩形有关:

InvalidateRect 产生一个无效矩形,并生成WM_PAINT消息

ValidateRect 使无效矩形区有效

GetUpdateRect 获得无效矩形坐标(逻辑)

Windows为每个窗口保留一个PAINTSTRUCT结构,其中包含无效矩形区域的坐标值。

要想在自己的程序高效绘图、只绘制无效矩形,首先需要重载视图的OnUpdate成员函数。

virtual void CView::OnUpdate( CView*pSender, LPARAM lHint, CObject*pHint );

当调用文档的UpdateAllViews时,框架会自动调用OnUpdate函数,也可在视图类中直接调用该函数。OnUpdate函数一般是这样处理的:访问文档,读取文档的数据,然后对视图的数据成员或控制进行更新,以反映文档的改动。可以用OnUpdate函数使视图的某部分无效。以便触发视的OnDraw,利用文档数据重绘窗口。缺省的OnUpdate使窗口整个客户区都无效,在重新设计时,要利用提示信息lHint和pHint定义一个较小的无效矩形。修改后的OnUpdate成员函数如清单8.5。

清单8.5 修改后的OnUpdate成员函数

void CDrawView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)

{

// TODO: Add your specialized code here and/or call the base class

// The document has informed this view that some data has changed.

 

if (pHint != NULL)

{

if (pHint->IsKindOf(RUNTIME_CLASS(CStroke)))

{

// The hint is that a stroke as been added (or changed).

// So, invalidate its rectangle.

CStroke* pStroke = (CStroke*)pHint;

CClientDC dc(this);

OnPr

首页 上一页 1 2 3 4 5 6 下一页 尾页 3/6/6
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇VC密码框显示字符的终极设置方法 下一篇图形设备接口(学习笔记)

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目