?? chap09.htm
字號:
<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=gb2312"><META NAME="Generator" CONTENT="Microsoft Word 97"><TITLE> </TITLE><META NAME="Template" CONTENT="C:\MSOffice\Template\jjhou.dot"></HEAD><BODY><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2><P>第</FONT><FONT SIZE=2>XX</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>章</FONT><FONT SIZE=2> </FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>具體而微的繪圖程式</P><P> </P><P>在本章中我將為你示范如何在</FONT><FONT SIZE=2>C++Builder</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>中撰寫一個完整的繪圖程式。藉由這個程式的撰寫,你會更加了解</FONT><FONT SIZE=2>C++Builder</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>的</FONT><FONT SIZE=2> Canvas </FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>繪圖精神,而在撰寫這個程式的同時,我們也可將相關的技術做一個整體的檢閱。此繪圖程式的執行結果如下:</P><P> </P><P><IMG SRC="Image7.gif" WIDTH=492 HEIGHT=387></P><P> </P><P> </P><P>在此程式中我會以循序漸進的方式一步一步地帶領你完成整個程式,基本上這個程式和</FONT><FONT SIZE=2>C++Builder</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>內附的范例程式有幾分類似,但我必須要說明的是:在</FONT><FONT SIZE=2> C++Builder</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>中所附的范例程式是直接由原先在</FONT><FONT SIZE=2>Delphi</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>內以</FONT><FONT SIZE=2> Object Pascal </FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>所撰寫的范例程式修改而成,所以有部份程式的寫法大為違背</FONT><FONT SIZE=2>C++ </FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>式物件導向精神,在邁入</FONT><FONT SIZE=2>C++Builder </FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>的新世紀之後,我們當然希望寫出的程式是『系出名門,血統純正』的</FONT><FONT SIZE=2>C++ </FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>式的物件導向程式。而這就是我在本章中希望帶領你完成的程式。</P><P> </P></FONT><FONT SIZE=2><P>XX-01 </FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>關於滑鼠事件(</FONT><FONT SIZE=2>Mouse Event</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>)</P><P> </P><P>撰寫繪圖程式,首先要了解滑鼠事件,在</FONT><FONT SIZE=2>Windows</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>中定義了許多的滑鼠訊息(</FONT><FONT SIZE=2>Message</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>),而這些滑鼠訊息在</FONT><FONT SIZE=2>BCB</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>中就成為滑鼠事件了,為了要處理滑鼠事件,我們必須要選寫滑鼠事件處理程式:</P><P> </P></FONT><FONT FACE="華康細圓體,???" LANG="ZH-TW" SIZE=1><P>在</FONT><FONT SIZE=1>Windows</FONT><FONT FACE="華康細圓體,???" LANG="ZH-TW" SIZE=1>中定義的滑鼠訊息列表</P></FONT><FONT SIZE=1><P>WM_CAPTURECHANGED</P><P>WM_LBUTTONDBLCLK</P><P>WM_LBUTTONDOWN</P><P>WM_LBUTTONUP</P><P>WM_MBUTTONDBLCLK</P><P>WM_MBUTTONDOWN</P><P>WM_MBUTTONUP</P><P>WM_MOUSEACTIVATE</P><P>WM_MOUSEMOVE</P><P>WM_NCHITTEST</P><P>WM_NCLBUTTONDBLCLK</P><P>WM_NCLBUTTONDOWN</P><P>WM_NCLBUTTONUP</P><P>WM_NCMBUTTONDBLCLK</P><P>WM_NCMBUTTONDOWN</P><P>WM_NCMBUTTONUP</P><P>WM_NCMOUSEMOVE</P><P>WM_NCRBUTTONDBLCLK</P><P>WM_NCRBUTTONDOWN</P><P>WM_NCRBUTTONUP</P><P>WM_RBUTTONDBLCLK</P><P>WM_RBUTTONDOWN</P><P>WM_RBUTTONUP</P></FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2><P>表</FONT><FONT SIZE=2>XX-01 Windows</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>內滑鼠相關</FONT><FONT SIZE=2> Message</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>。</P><P> </P><P>雖然在</FONT><FONT SIZE=2>Windows</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>作業系統中定義了非常多的訊息,但是在</FONT><FONT SIZE=2>C++Builder </FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>中已經把龐大的訊息系統作適度的簡化了,并且不再以訊息的方式存在,而改以事件</FONT><FONT SIZE=2> (Event</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>)的處理方式,在本章的繪圖程式中,我們只要處理以下的幾個事件即可:</P><P> </P></FONT><FONT SIZE=2><P>OnMouseDown </FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>滑鼠鍵按下事件</P></FONT><FONT SIZE=2><P>OnMouseMove </FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>滑鼠移動事件</FONT><FONT SIZE=2> </P><P>OnMouseUp </FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>滑鼠鍵放開事件</P></FONT><FONT SIZE=2><P>OnClick </FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>任何滑鼠的點取</P><P> </P><P>在此,你可以很明顯地發現,在</FONT><FONT SIZE=2>C++Builder</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>的事件中并未將左右滑鼠鍵分別定義,而是以合并處理的方式,因此在收到以上滑鼠事件時,若你要分辨左右滑鼠事件時,必須在事件處理程式中判斷左右鍵。</P><P> </P><P>具備了基本的滑鼠事件認知後,我們開始進行後續的程式探索吧!</P><P> </P><P>為了讓你實際了解程式的細節,我希望將程式撰寫的步驟細節交代楚,在往下進行之前,我們先建立一個新的專案檔,并將其命名為</FONT><FONT SIZE=2> DrawMain</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>,同時將</FONT><FONT SIZE=2>Form</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>的</FONT><FONT SIZE=2>Color</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>性質設為黑色(</FONT><FONT SIZE=2>clBlack</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>),以便直接在上面畫圖。</P><P> </P></FONT><FONT SIZE=2><P>XX-02</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>滑鼠事件的處理</P><P> </P><P>當</FONT><FONT SIZE=2>C++ Builder</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>應用程式偵測到物件滑鼠事件時,它會檢查你是否定義該物件相對應的滑鼠事件處理程式,然後呼叫該函數,將相關參數傳給它。以</FONT><FONT SIZE=2>OnMouseDown</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>事件為例,它的事件處理程式模版如下:</P></FONT><FONT SIZE=2><P>void __fastcall TForm1::FormMouseDown(TObject *Sender, TMouseButton Button,</P><P>	TShiftState Shift, int X, int Y)</P><P>{</P><P>}</P><P> </P></FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2><P>它總共接收了以下幾個參數:</P></FONT><FONT SIZE=2><P>Sender </FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>引發該事件的軟體元件。</P></FONT><FONT SIZE=2><P>Button </FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>表示滑鼠的按鍵。它的值可為</FONT><FONT SIZE=2>mbLeft</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>(左鍵),</FONT><FONT SIZE=2>mbRight</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>(右鍵),</FONT><FONT SIZE=2>mbMiddle</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>(中間鍵)。</P></FONT><FONT SIZE=2><P>Shift </FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>用以表示事件發生的同時</FONT><FONT SIZE=2>Alt</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>,</FONT><FONT SIZE=2>Shift</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>及</FONT><FONT SIZE=2>Ctrl</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>叁鍵的狀態。</P></FONT><FONT SIZE=2><P>X,Y </FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>用以表示事件發生時之座標位置。</P><P> </P><P>在大多數的情況下,滑鼠事件的(</FONT><FONT SIZE=2>X,Y</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>)座標值是我們最為感興趣的項目,不過,有時候我們也需要靠</FONT><FONT SIZE=2>Button</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>鍵來判斷滑鼠的按鍵,或是需要利用</FONT><FONT SIZE=2>Shift</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>來取得特殊鍵的狀態,而做一些額外的程式處理。</P><P> </P></FONT><FONT SIZE=2><P>XX-02-01 OnMouseDown</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>事件的處理</P><P> </P><P>首先我們先以一個最基本的畫線程式來說明</FONT><FONT SIZE=2>OnMouseDown</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>事件的處理,當使用者按下滑鼠時,我們希望將筆移至事件發生時的坐標,因此我們可將程式寫成如下:</P><P> </P></FONT><FONT SIZE=2><P>void __fastcall TForm1::FormMouseDown(TObject *Sender, TMouseButton Button,</P><P>	TShiftState Shift, int X, int Y)</P><P>{</P><P>	Canvas->MoveTo(X,Y);</P><P>}</P><P>XX-02-03 OnMouseUp</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>事件的處理</P><P> </P><P>同樣地,我們可以再為這個</FONT><FONT SIZE=2>Form</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>加上</FONT><FONT SIZE=2>OnMouseUp</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>的事件處理函式,在收到</FONT><FONT SIZE=2>OnMouseUp</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>事件時,由滑鼠點下的坐標,畫一條直線至現在的坐標。</P><P> </P></FONT><FONT SIZE=2><P>void __fastcall TForm1::FormMouseUp(TObject *Sender, TMouseButton Button,</P><P>	TShiftState Shift, int X, int Y)</P><P>{</P><P>	Canvas->LineTo(X,Y);</P><P>}</P><P> </P></FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2><P>在寫完了以上兩個事件處理函式之後,我們就可以在</FONT><FONT SIZE=2>Form</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>上面作畫了,你可以用滑鼠在</FONT><FONT SIZE=2>Form</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>上面拖戈出一條條直線。其執行結果大致如圖</FONT><FONT SIZE=2>XX-01</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>:</P><P> </P><P><IMG SRC="Image8.gif" WIDTH=348 HEIGHT=240></P><P>圖</FONT><FONT SIZE=2>XX-01</P><P>XX-02-02 OnMouseMove</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>事件的處理</P><P> </P><P>在加上了</FONT><FONT SIZE=2>OnMouseDown</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>及</FONT><FONT SIZE=2>OnMouseUp</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>處理函式之後,我們只能畫出一條條直線,若是我們想要以滑鼠畫出不規則線段時,就必須再處理</FONT><FONT SIZE=2>OnMouseMove</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>事件,利用</FONT><FONT SIZE=2>OnMouseMove</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>事件,我們可以追縱到滑鼠移動的位置,簡單的</FONT><FONT SIZE=2>OnMouseMove</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>事件處理函式如下:</P><P> </P></FONT><FONT SIZE=2><P>void __fastcall TForm1::FormMouseMove(TObject *Sender, TShiftState Shift, int X,</P><P>	int Y)</P><P>{</P><P>	Canvas->LineTo(X,Y);</P><P>}</P><P> </P></FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2><P>此程式的意義即在於將滑鼠所經過的每個點,以線條連接起來,在加上</FONT><FONT SIZE=2>OnMouseMove </FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>事件處理函式之後,它的執行結果會變成圖</FONT><FONT SIZE=2>XX-02</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>:</P><P><IMG SRC="Image9.gif" WIDTH=348 HEIGHT=240></P><P>圖</FONT><FONT SIZE=2>XX-02</P><P>XX-02-03	</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>滑鼠的處理的加強</P><P> </P><P>前面的程式對於滑鼠的移動處理有部份考慮的不夠周詳,因為它在滑鼠移動時不分青紅皂白就將線畫在螢慕上,造成螢幕上的線條混亂,這并不是正規的處理方法,正確的處理方法應該如下:</P><P> </P></FONT><FONT SIZE=2><P>(1) </FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>滑鼠鍵按下時,將記錄滑鼠按下的旗標設為</FONT><FONT SIZE=2>True.</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>同時將該點記錄下來,謂之原點。</P><OL START=2><LI>滑鼠移動時,判斷滑鼠按下的旗標是否設為</FONT><FONT SIZE=2> True</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>,若為</FONT><FONT SIZE=2> True</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>,則移動至原點,并畫一條由原點至目前所在點的線。同時更新原點位置至目前所在之點。</LI><LI VALUE=3>滑鼠放開時,將記錄滑鼠按下的旗標設為</FONT><FONT SIZE=2>False</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>。</LI></OL><P> </P><P>以下就是關於叁個滑鼠事件的處理程式碼。</P><P> </P></FONT><FONT SIZE=2><P>// </FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>滑鼠按下的事件處理函式</P></FONT><FONT SIZE=2><P>// 1. </FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>將旗標設為</FONT><FONT SIZE=2>True</P><P>// 2. </FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>記錄原點位置</P></FONT><FONT SIZE=2><P>void __fastcall TForm1::FormMouseDown(TObject *Sender, TMouseButton Button,</P></FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2><P>	</FONT><FONT SIZE=2>TShiftState Shift, int X, int Y)</P></FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2><P>{</P></FONT><FONT SIZE=2><P> m_bDraw = TRUE;</P><P> m_nOrgX=X;</P><P> m_nOrgY=Y;</P></FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2><P>}</P><P> </P></FONT><FONT SIZE=2><P>// </FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>滑鼠移動的事件處理函式</P></FONT><FONT SIZE=2><P>// 1. </FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>判斷旗標是否為</FONT><FONT SIZE=2>True</FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>。若是則進行以下動作。</P></FONT><FONT SIZE=2><P>// 2. </FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>移動至原點。</P></FONT><FONT SIZE=2><P>// 3. </FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>畫一條由原點至目前所在點的線條。</P></FONT><FONT SIZE=2><P>// 4. </FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>更改原點位置。</P><P> </P></FONT><FONT SIZE=2><P>void __fastcall TForm1::FormMouseMove(TObject *Sender, TShiftState Shift,</P></FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2><P>	</FONT><FONT SIZE=2>int X, int Y)</P></FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2><P>{</P><P>	</FONT><FONT SIZE=2>if (m_bDraw)</P><P> {</P><P> 	Canvas->MoveTo(m_nOrgX,m_nOrgY);</P><P> Canvas->LineTo(X,Y);</P><P> m_nOrgX = X;</P><P> m_nOrgY = Y;</P></FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2><P>	}</P><P>}</P><P> </P></FONT><FONT SIZE=2><P>// </FONT><FONT FACE="新細明體" LANG="ZH-TW" SIZE=2>滑鼠放開的事件處理函式</P>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -