📄 chap8_3.htm
字号:
<p>{</p>
<p>CPen penStroke;</p>
<p>if (!penStroke.CreatePen(PS_SOLID, m_nPenWidth, RGB(0,0,0)))</p>
<p>return FALSE;</p>
<p>CPen* pOldPen = pDC->SelectObject(&penStroke);</p>
<p>pDC->MoveTo(m_pointArray[0]);</p>
<p>for (int i=1; i < m_pointArray.GetSize(); i++)</p>
<p>{</p>
<p>pDC->LineTo(m_pointArray[i]);</p>
<p>}</p>
<p>pDC->SelectObject(pOldPen);</p>
<p>return TRUE;</p>
<p>}</p>
<p></font><font SIZE="3"><b> </p>
<p></b><font color="#3973DE">鼠标绘图</font></font><font FACE="Times New Roman" SIZE="3"></p>
<p ALIGN="JUSTIFY"></font><font SIZE="3">鼠标绘图基本过程是:用户按下鼠标左键时开始绘图,在鼠标左键按下且移动过程中不断画线跟踪鼠标位置,当松开鼠标左键结束绘图。因此,需要处理三个消息:</font><font FACE="Times New Roman" SIZE="3">WM_LBUTTONDOWN</font><font SIZE="3">、</font><font FACE="Times New Roman" SIZE="3">WM_MOUSEMOVE</font><font SIZE="3">、</font><font FACE="Times New Roman" SIZE="3">WM_LBUTTONUP</font><font SIZE="3">。用</font><font FACE="Times New Roman" SIZE="3">ClassWizard</font><font SIZE="3">为上述三个消息生成消息处理函数,并在其中手工加入代码,修改后的成员函数如下:</font><font FACE="Times New Roman" SIZE="3"></p>
<p ALIGN="JUSTIFY"></font><b><font SIZE="3"> </p>
<p ALIGN="JUSTIFY">清单</font><font FACE="Times New Roman" SIZE="3">8.8 </font><font SIZE="3">鼠标消息处理函数</font><font FACE="Times New Roman" SIZE="3">OnLButtonDown()</b></p>
<p>void CDrawView::OnLButtonDown(UINT nFlags, CPoint point) </p>
<p>{</p>
<p>// TODO: Add your message handler code here and/or call default</p>
<p>// Pressing the mouse button in the view window starts a new stroke</p>
<p>// CScrollView changes the viewport origin and mapping mode.</p>
<p>// It's necessary to convert the point from device coordinates</p>
<p>// to logical coordinates, such as are stored in the document.</p>
<p>CClientDC dc(this);</p>
<p>OnPrepareDC(&dc);</p>
<p>dc.DPtoLP(&point);</p>
<p>m_pStrokeCur = GetDocument()->NewStroke();</p>
<p>// Add first point to the new stroke</p>
<p>m_pStrokeCur->m_pointArray.Add(point);</p>
<p>SetCapture(); // Capture the mouse until button up.</p>
<p>m_ptPrev = point; // Serves as the MoveTo() anchor point for the</p>
<p>// LineTo() the next point, as the user drags the</p>
<p>// mouse.</p>
<p>return;</p>
<p>}</p>
<p></font><font SIZE="3"> </font><font FACE="Times New Roman" SIZE="3"></p>
<p></font><font SIZE="3">在鼠标左键按下,首先获得鼠标按下的位置坐标。由于它是设备坐标,因此先用</font><font FACE="Times New Roman" SIZE="3">DPToLP</font><font SIZE="3">将它转换为逻辑坐标。在此之前,要用</font><font FACE="Times New Roman" SIZE="3">OnPrepareDC()</font><font SIZE="3">对视图坐标原点进行调整。然后用</font><font FACE="Times New Roman" SIZE="3">CDrawDoc</font><font SIZE="3">的</font><font FACE="Times New Roman" SIZE="3">NewStroke()</font><font SIZE="3">成员函数创建一个笔划对象,并将笔划对象加入到笔划链表中。然后,将当前点坐标加入道笔划对象内部的点数组中。以后,当鼠标移动时,</font><font FACE="Times New Roman" SIZE="3">OnMouseMove</font><font SIZE="3">就不断修改该笔划对象的内部数据成员(加入新的点到笔划对象的数组中)。另外,为了用</font><font FACE="Times New Roman" SIZE="3">LineTo</font><font SIZE="3">画出线条,需要将当前鼠标位置保存到</font><font FACE="Times New Roman" SIZE="3">m_ptPrev</font><font SIZE="3">中,以便出现一个新的点时,画一条从</font><font FACE="Times New Roman" SIZE="3">m_ptPrev</font><font SIZE="3">到新的点的直线。</font><font FACE="Times New Roman" SIZE="3"></p>
<p></font><font SIZE="3">但是,由于用户的鼠标可以在屏幕上任意移动。当鼠标移出窗口外时,窗口无法收到鼠标消息。此时,如果松开了鼠标左键,应用程序由于无法接受到该条消息而不会终止当前笔划,这样就造成了错误。如何避免这种情况发生呢?解决的办法是要让窗口在鼠标移出窗口外时仍然能接受到鼠标消息。幸好,</font><font FACE="Times New Roman" SIZE="3">Windows</font><font SIZE="3">提供了一个</font><font FACE="Times New Roman" SIZE="3">API</font><font SIZE="3">函数</font><font FACE="Times New Roman" SIZE="3">SetCapture()</font><font SIZE="3">解决了这一问题。</font><font FACE="Times New Roman" SIZE="3"></p>
<p>CWnd::SetCapture()</font><font SIZE="3">用于捕获鼠标:无论鼠标光标位置在何处,都会将鼠标消息送给调用它的那一个窗口。在用完后,需要用</font><font FACE="Times New Roman" SIZE="3">ReleaseCapture()</font><font SIZE="3">释放窗口对鼠标的控制,否则其他窗口将无法接收到鼠标消息。这一工作当然最好在鼠标左键松开</font><font FACE="Times New Roman" SIZE="3">OnLButtonUp()</font><font SIZE="3">时来做。<b></p>
<p>清单</font><font FACE="Times New Roman" SIZE="3">8.9 OnLButtonUp</font><font SIZE="3">消息处理函数</font></b><font FACE="Times New Roman" SIZE="3"></p>
<p>void CDrawView::OnLButtonUp(UINT nFlags, CPoint point) </p>
<p>{</p>
<p>// TODO: Add your message handler code here and/or call default</p>
<p></font><font SIZE="3"> </font><font FACE="Times New Roman" SIZE="3"></p>
<p>// Mouse button up is interesting in the draw application</p>
<p>// only if the user is currently drawing a new stroke by dragging</p>
<p>// the captured mouse.</p>
<p>if (GetCapture() != this)</p>
<p>return; // If this window (view) didn't capture the mouse,</p>
<p>// then the user isn't drawing in this window.</p>
<p>CDrawDoc* pDoc = GetDocument();</p>
<p>CClientDC dc(this);</p>
<p>// CScrollView changes the viewport origin and mapping mode.</p>
<p>// It's necessary to convert the point from device coordinates</p>
<p>// to logical coordinates, such as are stored in the document.</p>
<p>OnPrepareDC(&dc); // set up mapping mode and viewport origin</p>
<p>dc.DPtoLP(&point);</p>
<p>CPen* pOldPen = dc.SelectObject(pDoc->GetCurrentPen());</p>
<p>dc.MoveTo(m_ptPrev);</p>
<p>dc.LineTo(point);</p>
<p>dc.SelectObject(pOldPen);</p>
<p>m_pStrokeCur->m_pointArray.Add(point);</p>
<p>// Tell the stroke item that we're done adding points to it.</p>
<p>// This is so it can finish computing its bounding rectangle.</p>
<p>m_pStrokeCur->FinishStroke();</p>
<p>// Tell the other views that this stroke has been added</p>
<p>// so that they can invalidate this stroke's area in their</p>
<p>// client area.</p>
<p>pDoc->UpdateAllViews(this, 0L, m_pStrokeCur);</p>
<p>ReleaseCapture(); // Release the mouse capture established at</p>
<p>// the beginning of the mouse drag.</p>
<p>return;</p>
<p>}</p>
<p></font><font SIZE="3"> </font><font FACE="Times New Roman" SIZE="3"></p>
<p>OnLButtonUp</font><font SIZE="3">首先检查鼠标是否被当前窗口所捕获,如果不是则返回。然后画出笔划最后两点之间的极短的直线段。接着,调用</font><font FACE="Times New Roman" SIZE="3">CStroke::FinishStroke()</font><font SIZE="3">,请求</font><font FACE="Times New Roman" SIZE="3">CStroke</font><font SIZE="3">对象计算它的最小矩形。然后调用</font><font FACE="Times New Roman" SIZE="3">pDoc->UpdateAllViews(this, 0L, m_pStrokeCur)</font><font SIZE="3">通知其他视图更新显示。</font><font FACE="Times New Roman" SIZE="3"></p>
<p></font><font SIZE="3">当一个视图修改了文档内容并更新显示时,一般的其它的对应于同一文档的视图也需要相应更新,这通过调用文档的成员函数</font><font FACE="Times New Roman" SIZE="3">UpdateAllViews</font><font SIZE="3">完成。</font><font FACE="Times New Roman" SIZE="3"></p>
<blockquote>
<blockquote>
<p>void UpdateAllViews( CView* pSender, LPARAM lHint = 0L, CObject* pHint = </p>
<p>NULL );</p>
<b>
</blockquote>
</blockquote>
<p></b>UpdateAllViews</font><font SIZE="3">带三个参数:</font><font FACE="Times New Roman" SIZE="3">pSender</font><font SIZE="3">指向修改文档的视图。由于该视图已经作了更新,所以不再需要更新。比如,在上面的例子中,</font><font FACE="Times New Roman" SIZE="3">OnLButtonUp</font><font SIZE="3">已经绘制了视图,因此不需要再次更新。如果为</font><font FACE="Times New Roman" SIZE="3">NULL</font><font SIZE="3">,则文档对应的所有视图都被更新。</font><font FACE="Times New Roman" SIZE="3"></p>
<p>lHint</font><font SIZE="3">和</font><font FACE="Times New Roman" SIZE="3">pHint</font><font SIZE="3">包含了更新视图时所需的附加信息。在本例中,其他视图只需要重画当前绘制中的笔划,因此</font><font FACE="Times New Roman" SIZE="3">OnLButtonUp</font><font SIZE="3">把当前笔划指针传给</font><font FACE="Times New Roman" SIZE="3">UpdateAllViews</font><font SIZE="3">函数。该函数调用文档所对应的除</font><font FACE="Times New Roman" SIZE="3">pSender</font><font SIZE="3">外的所有视图的</font><font FACE="Times New Roman" SIZE="3">OnUpdate</font><font SIZE="3">函数,并将</font><font FACE="Times New Roman" SIZE="3">lHint</font><font SIZE="3">和</font><font FACE="Times New Roman" SIZE="3">pHint</font><font SIZE="3">传给</font><font FACE="Times New Roman" SIZE="3">OnUpdate</font><font SIZE="3">函数通知更新附加信息。</font><font FACE="Times New Roman" SIZE="3"></p>
<p>OnLButtonUp</font><font SIZE="3">最后释放对鼠标的控制,这样别的应用程序窗口就可以获得鼠标消息了。</font><font FACE="Times New Roman" SIZE="3"></p>
<p></font><font SIZE="3">结合上面讲到的知识,读者不难自行理解下面的</font><font FACE="Times New Roman" SIZE="3">OnMouseMove</font><font SIZE="3">函数。</font><font FACE="Times New Roman" SIZE="3"></p>
<p>void CDrawView::OnMouseMove(UINT nFlags, CPoint point) </p>
<p>{</p>
<p>// TODO: Add your message handler code here and/or call default</p>
<p>// Mouse movement is interesting in the Scribble application</p>
<p>// only if the user is currently drawing a new stroke by dragging</p>
<p>// the captured mouse.</p>
<p>if (GetCapture() != this)</p>
<p>return; // If this window (view) didn't capture the mouse,</p>
<p>// then the user isn't drawing in this window.</p>
<p>CClientDC dc(this);</p>
<p>// CScrollView changes the viewport origin and mapping mode.</p>
<p>// It's necessary to convert the point from device coordinates</p>
<p>// to logical coordinates, such as are stored in the document.</p>
<p>OnPrepareDC(&dc);</p>
<p>dc.DPtoLP(&point);</p>
<p>m_pStrokeCur->m_pointArray.Add(point);</p>
<p>// Draw a line from the previous detected point in the mouse</p>
<p>// drag to the current point.</p>
<p>CPen* pOldPen = dc.SelectObject(GetDocument()->GetCurrentPen());</p>
<p>dc.MoveTo(m_ptPrev);</p>
<p>dc.LineTo(point);</p>
<p>dc.SelectObject(pOldPen);</p>
<p>m_ptPrev = point;</p>
<p>return;</p>
<p>}</p>
<p></font><font SIZE="3">至此,绘图程序的文档、视图全部设计完了,现在编译运行程序。程序启动后,在空白窗口中徒手绘图,如图</font><font FACE="Times New Roman" SIZE="3">8-7</font><font SIZE="3">所示。</font><font FACE="Times New Roman" SIZE="3"></p>
<p align="center"></font><img src="T8_7.gif" alt="T8_7.tif (267124 bytes)" WIDTH="470" HEIGHT="335"><font FACE="Times New Roman" SIZE="4"><b></p>
</b></font><p align="center"><font SIZE="3">图</font><font FACE="Times New Roman" SIZE="3">8-7 </font><font SIZE="3">多文档绘图程序窗口</font></p>
<div align="center"><center><table border="0" cellpadding="0" cellspacing="0" width="615">
<tr>
<td><a href="chap8_2.htm">上一页</a></td>
<td><p align="right"><a href="chap8_4.htm">下一页</a></td>
</tr>
</table>
</center></div><font SIZE="5"><hr noshade color="#3973DE" size="1">
<p align="center"></font><font size="2" color="#000000">本教程由<a href="http://vcdynasty.yeah.net">Visual C++王朝(Where programmers come together)</a>协助制作<br>
未经许可,请勿以任何形式复制</font></td>
<b>
</tr>
</table>
</center></div>
<p ALIGN="CENTER"></b><font SIZE="5"> </font><font FACE="Times New Roman" SIZE="5"></p>
</font><font FACE="Times New Roman" SIZE="3">
<p></font><b><font SIZE="3"> </font><font FACE="Times New Roman" SIZE="3"></p>
</font></b>
<p><font SIZE="3"> </font><font FACE="Times New Roman" SIZE="3"></p>
<p></font> </p>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -