按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
#0168 // drag to the current point。
#0169 CPen* pOldPen = dc。SelectObject(GetDocument()…》GetCurrentPen());
#0170 dc。MoveTo(m_ptPrev);
#0171 dc。LineTo(point);
#0172 dc。SelectObject(pOldPen);
492
…………………………………………………………Page 555……………………………………………………………
第8章 Document…View 深入探討
#0173 m_ptPrev = point;
#0174 return;
#0175 }
View 的重绘动作:GetDocument 和OnDraw
以下是CScribbleView 中与重绘动作有关的成员变量和成员函数。
CScribbleView 的成员变量
m_pStrokeCur :一个指针,指向目前正在工作的线条。
m_ptPrev :线条中的前一个工作点。我们将在这个点与目前鼠标按下的点之间
画一条直线。虽说理想情况下鼠标轨迹的每一个点都应该被记录下来,但如果
鼠标移动太快来不及记录,只好在两点之间拉直线。
CScribbleView 的成员函数
OnDraw :这是一个虚拟函数,负责将Document 的数据显示出来。改写它是程
式员最大的责任之一。
GetDocument:AppWizard 为我们做出这样的码,以inline 方式定义于头文件:
inline CScribbleDoc* CScribbleView::GetDocument()
{ return (CScribbleDoc*)m_pDocument; }
其中m_pDocument 是CView 的成员变量。我们可以推测,当程序设定好Document
Template 之后,每次Framework 动态产生View 对象,其内的m_pDocument 已经被
Framework 设定指向对应之Document 了。
View 对象何时被动态产生?答案是当使用者选按【File/Open 】或【File/New 】。每
当产生一个Document ,就会产生一组Document/View/Frame 「三口组」。
OnPreparePrinting,OnBeginPrinting,OnEndPrinting:这三个CView 虚拟函数将
用来改善打印行为。AppWizard 只是先帮我们做出空函数。第12 章才会用到
它们。
493
…………………………………………………………Page 556……………………………………………………………
第篇 深入 MFC 程式設計
我们来看看CView 之中居最重要地位的OnDraw,面对Scribble Document 的数据结构,
将如何进行绘图动作。为了获得资料,OnDraw 一开始先以GetDocument 取得Document
对象指针;然后以while 循环一一取得各线条,再调用CStroke::DrawStroke 绘图。想象
中绘图函数应该放在View 类别之内(绘图不正是View 的责任吗),但是DrawStroke 却
否!原因是把线条的资料和绘图动作一并放在CStroke 中是最好的包装方式。
void CScribbleView::OnDraw(CDC* pDC)
{
CScribbleDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// The view delegates the drawing of individual strokes to
// CStroke::DrawStroke()。
CTypedPtrList& strokeList = pDoc…》m_strokeList;
POSITION pos = strokeList。GetHeadPosition ();
while (pos != NULL)
{
CStroke* pStroke = strokeList。GetNext (pos);
pStroke…》DrawStroke(pDC);
}
}
其中用到两个CObList 成员函数:
GetNext:取得下一个元素。
GetHeadPosition:传回串行之第一个元素的「位置」。传回来的「位置」是一
个类型为POSITION 的数值,这个数值可以被使用于CObList 的其它成员函数
中,例如GetAt 或SetAt 。你可以把「位置」想象是串行中用以标示某个节点
node )的指针。当然,它并不真正是指针。
(
494
…………………………………………………………Page 557……………………………………………………………
第8章 Document…View 深入探討
View 与使用者的交谈 (鼠标消息处理实例)
为了实现「以鼠代笔」的功能,CScribbleView 必须接受并处理三个消息:
BEGIN_MESSAGE_MAP(CScribbleView; CView)
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
。。。
END_MESSAGE_MAP()
三个消息处理例程的的内容总括来说就是追踪鼠标轨迹、在窗口上绘图、以及调用CStroke
成员函数以修正线条内容……包括产生一个新的线条空间以及不断把坐标点加上去。三
个函数的重要动作摘记于下。这些函数的骨干及其在Messape Map 中的映射项目,不劳
我们动手,有ClassWizard 代劳。下一个小节我会介绍其操作方法。
void CScribbleView::OnLButtonDown(UINT nFlags; CPoint point)
{
// 当鼠标左键按下,
// 利用CScribbleDoc::NewStroke 产生一个新的线条空间;
// 利用CArray::Add 把这个点加到线条上去;
// 调用SetCapture 取得鼠标捕捉权(mouse capture);
// 把这个点记录为「上一点」(m_ptPrev);
}
void CScribbleView::OnMouseMove(UINT; CPoint point)
{
// 当鼠标左键按住并开始移动,
// 利用CArray::Add 把新坐标点加到线条上;
// 在上一点(m_ptPrev)和这一点之间画直线;
// 把这个点记录为「上一点」(m_ptPrev);
}
void CScribbleView::OnLButtonUp(UINT; CPoint point)
{
// 当鼠标左键放开,
// 在上一点(m_ptPrev)和这一点之间画直线;
// 利用CArray::Add 把新的点加到线条上;
495
// 调用ReleaseCapture() 释放鼠标捕捉权(mouse capture)。
}
…………………………………………………………Page 558……………………………………………………………
第篇 深入 MFC 程式設計
ClassWizard 的辅佐
前述三个CScribbleView 成员函数(OnLButtonDown,OnLButtonUp,OnMouseMove)是
Message Map 的一部份,ClassWizard 可以很方便地帮�