Download presentation
Presentation is loading. Please wait.
1
第 10 章 事件驅動程式設計
2
本章重點提要 10-1 事件驅動的觀念 10-2 設計事件驅動的程式 10-3 表單事件 10-4 滑鼠事件 10-5 鍵盤事件
3
本章閱讀建議 從第 4 章建立表單應用程式開始, 我們所撰寫的表單應用程式, 其實都是由各式各樣的事件程序 (Event Handler) 組成, 這種程式設計的方法稱為事件驅動 (Event-Driven) 程式設計。 而事件程序和前一章介紹的一般程序有什麼不同、特色?除了常用的按鈕事件及前幾章使用過的事件外, 還有哪些事件可讓我們建立相關事件程序?都是本章的重點。
4
本章閱讀建議 10-1 事件驅動的觀念:從觀念出發, 深入瞭解什麼是事件、什麼是事件驅動的程式設計。
10-2 設計事件驅動的程式:瞭解什麼是事件驅動後, 先熟悉在 VB 中建立事件程序的各種方法。 10-3 表單事件:表單本身有一些特殊事件, 我們就以此為出發點, 來練習處理事件。
5
本章閱讀建議 10-4 滑鼠事件:滑鼠的事件非常多, 簡單的一項滑鼠操作動作,就會產生一連串的滑鼠事件, 本節要告訴大家如何處理、應用滑鼠事件。 10-5 鍵盤事件:對於鍵盤事件, 最基本的應用就是判斷使用者按下什麼按鍵、或是按鍵組合 (例如同時按了[Ctrl] 、[Shift] 等按鍵
6
10-1 事件驅動的觀念 事件驅動 (Event-Driven) 程式設計是 Windows 程式設計的一項特色, 它和傳統程序式 (Procedural) 程式設計 (例如主控台應用程式)相當不同:在程序式程式設計的架構中, 程式流程基本上是由程式的開頭『依序』執行到程式結尾, 在呼叫函式時雖會暫時離開, 但函式執行完畢, 執行流程仍會回到主程式, 繼續往下一行、一行地執行。
7
事件驅動的觀念 但在事件驅動程式設計中, 就不是撰寫依序從頭執行到尾的一串程式, 而是撰寫多段對應到不同事件的程序。一般性的事件包括使用者的各項操作動作, 例如按下視窗中的按鈕、按下鍵盤按鍵、移動滑鼠等等;另一類事件則是由作業系統或應用程式產生的, 例如表單的載入、關閉等事件。
8
事件驅動的觀念 以第 4 章猜謎遊戲的範例程式為例, 表單提供了 2 個輸入欄位, 當使用者輸入答案, 按下 鈕, 就會觸發其 Click 事件, 系統會呼叫對應於該事件的 Click 事件程序, 該程序就會檢查使用者輸入的答案, 並顯示結果。
9
事件驅動的觀念 但如果將這個程式改寫成程序式程式, 設計的方式就不同了。以主控台應用程式來撰寫, 程式執行的方式可能是依序顯示訊息, 請使用者分別輸入『羊來了』、『狼來了』的答案, 然後顯示檢查結果, 接著就結束程式了。
10
事件驅動的觀念
11
事件驅動的觀念 在程序式程式設計的架構下, 當程式已設計成要按照『羊來了』、『狼來了』的順序輸入時, 使用者也只能按照這樣的順序輸入, 輸入完成後, 程式就會檢查答案並顯示之。即使程式改成用迴圈讓使用者可重複猜, 第 2 次、第 3 次...的流程也相同, 仍是要依序輸入『羊來了』、『狼來了』的答案, 也不能自己決定先輸入『狼來了』的答案, 再輸入『羊來了』的答案。
12
事件驅動的觀念 但在事件驅動程式設計之中, 則無這樣的強制性流程, 程式啟動後顯示表單, 接下來要如何操作就完全由使用者自行控制, 例如要依『羊來了→狼來了』或『狼來了→羊來了』的順序輸入均可, 而且輸入到第二個答案時, 發現前一個有錯也仍可回頭修改。在程序式程式中, 一但輸入答案後 (按了[Enter] 鍵), 就不能回頭修改了。
13
10-2 設計事件驅動的程式 在 VB 中建立 Windows Form 應用程式專案時, 就是使用事件驅動的方式來設計程式。在其架構下, 各控制項及表單物件, 都可以是事件發生的來源。在 .NET Framework 中的控制項及表單類別,均已事先定義好它們可能發生的事件名稱, 讓我們可針對這些事件進行處理。
14
設計事件驅動的程式 例如在表單中按一下滑鼠左鈕, 就會觸發表單的 Click 事件;如果是按鍵盤按鍵, 則會觸發表單的 KeyDown 等相關事件。同理, 如果相同動作發生在表單中的控制項上, 也會觸發該控制項的相關事件。
15
設計事件驅動的程式 我們可以發現, 使用者的各種操作動作, 都會觸發對應的事件, 但程式是否要對該事件做回應, 就由我們自行決定。而處理事件的程序, 我們稱為事件程序 (Event Handler, 或稱事件處理程序)。當事件發生時, 系統就會用與事件相關的資料當參數, 呼叫我們寫好的事件程序:
16
設計事件驅動的程式
17
設計事件驅動的程式 如果事件沒有對應的事件程序, 就算發生事件, 程式也不會有任何反應。舉例來說, 上例的程式中, 如果根本沒有標示『HandlesButton1.Click』的程序, 那麼使用者按按鈕, 程式也不會做處理。
18
事件程序的格式 事件程序也是程序的一種, 只不過在定義時多了幾個關鍵字, 也有其特殊的參數, 以下是典型的按鈕事件程序格式:
19
事件程序的格式 存取層級:在 Sub 關鍵字前面的 Private 關鍵字, 是用來標示此程序『不能』被類別以外的程式存取。VB 在建立事件程序時,都會自動加上 Private 關鍵字, 我們不需更動, 也請不要將它刪除。 程序名稱:預設由 VB 自動產生的事件程序, 都是用『控制項名稱_事件名稱』的方式替程序命名。雖然這種命名方式, 通常能讓我們較易看出程序的用途, 但有時控制項或事件名稱過長、名稱相近, 也會造成閱讀不便, 此時我們可適時修改其名稱, 稍後也會介紹如何指定自訂名稱來建立事件程序的方法。
20
事件程序的格式 參數 1:事件來源 (sender):事件程序第一個參數表示事件的發生處, 例如在 Button1 的 Click 事件程序中, 傳來的 sender參數就是代表 Button1 物件, 因此我們可透過此參數來存取該物件。 參數 2:事件參數:事件程序第 2 個參數包含與此事件相關的資訊, 通常不會用到。但對於本章稍後會介紹的滑鼠、鍵盤等事件, 則第 2 個參數會有包括滑鼠座標、按鍵碼等資訊可應用。
21
事件程序的格式 Handles 關鍵字:在事件程序最後面的 Handles 關鍵字, 是用來表示此程序所要處理的事件。事件名稱格式為『控制項名稱.事件名稱』, 例如 Button1.Click 就代表 Button1 控制項的Click 事件。所以當使用者在 Button1 上按一下觸發其 Click 事件時, 系統就會呼叫註明了『Handles Button1.Click』的程序:
22
事件程序的格式 Handles 關鍵字後可列出多個事件, 讓同一個程序處理多個事件,稍後即會說明如何讓同一程序處理多個事件。
雖然定義事件程序時, 要寫出事件參數、所處理的事件等多項資訊, 所幸利用 VB 的操作介面, 即可自動建立事件程序, 我們只需編寫事件程序中的程式即可。
23
建立事件程序的方法 VB 支援三種建立事件程序的方法:
在控制項上雙按:這是我們最常使用的方式。在 VB 的表單設計視窗中, 於控制項上雙按, VB 就會產生該控制項的『預設』事件程序。前幾章介紹的控制項及其預設事件如下表所列:
24
建立事件程序的方法 若要建立非預設事件的事件程序, 則可用另外兩個方法。
由程式碼視窗上方的下拉式選單建立:在第 4 章用此方法建立過表單的 Load 事件程序, 此法適合於建立非預設事件的處理程序:
25
建立事件程序的方法
26
建立事件程序的方法 以下就用一個簡單的例子, 來看如何由屬性窗格建立各種事件程序。
由『屬性』窗格建立:此法是最具彈性的方法。因為可在建立事件程序之前, 即自行指定程序名稱 (前兩種方式都只會建立『控制項名稱_事件名稱』格式的程序名稱), 且也可將多個事件都指向同一事件程序, 請參考以下的上機練習。 以下就用一個簡單的例子, 來看如何由屬性窗格建立各種事件程序。
27
建立事件程序的方法 練習由屬性窗格建立事件程序及自訂事件程序名稱。 建立專案 Ch10-01, 並加入兩個 控制項。
28
建立事件程序的方法 選取 Button1 控制項, 在屬性窗格中按 鈕, 就會列出此控制項的所有事件。找到 Click 事件後, 用滑鼠在上面雙按, 就會建立以『控制項名稱_ 事件名稱』格式命名的事件程序:
29
建立事件程序的方法
30
建立事件程序的方法 如果要自訂事件程序的名稱, 可在屬性窗格中直接輸入,例如:
31
建立事件程序的方法 通常在 VB 產生的程序名稱過長, 或我們想讓單一程序處理多個事件時, 較需要自訂事件程序名稱, 以便於閱讀。
32
用單一事件程序處理多個事件 有時候我們會想讓不同控制項的同一事件 (例如好幾個按鈕的Click 事件), 都以相同的邏輯來處理, 此時我們就可讓它們共用同一個事件程序, 或者說用單一個事件程序來處理多個事件。 要讓單一事件程序可處理多個事件, 原則上就是修改 Handles 關鍵字後面所列的事件, 將它從單一事件, 改以逗號分隔條列多個事件即可。若在事件程序之中, 要判斷事件來源是誰, 則可從事件程序的第 1 個參數 Sender, 來判斷事件來源, 並做相關處理。
33
用單一事件程序處理多個事件 用單一事件程序處理多個 Click 事件。 建立專案 Ch10-02, 並加入三個 控制項, 以及 控制項。
34
用單一事件程序處理多個事件 讓 Handles 關鍵字後面列出多個事件, 可以手動在現有事件後面, 加上逗號並輸入另一個事件名稱, 例如:
35
用單一事件程序處理多個事件
36
用單一事件程序處理多個事件 在共用的事件程序中, 可做各事件共同要處理的動作。若需判斷事件來源, 或對事件來源做個別處理, 則可透過事件程序第 1 個參數 sender, 即可存取到事件來源的控制項。例如我們希望每個按鈕被按下時, 將 Label1 控制項的數字加 1;被按下的按鈕本身的數字 (Text 屬性) 也加 1, 則可寫成如下程式:
37
用單一事件程序處理多個事件 按[F5] 鍵執行程式, 就可按鈕測試共用的事件程序之效果:
38
10-3 表單事件 雖然在撰寫表單應用程式時, 最常用到的仍是各控制項的『預設』事件, 例如 Button 控制項的 Click 事件, 但有時候我們也會利用其它事件, 讓程式產生不同的效果。本節先介紹屬於表單的事件。
39
表單的開始與結束 許多應用程式會在開始、結束執行時, 進行一些準備或善後工作。例如在開始執行時, 讀取設定檔、進行初始化工作等等;在程式結束時, 則是寫回設定檔、詢問使用者是否要將未儲存的資料存檔等等。而代表表單的 Form 類別, 就提供了以下事件, 讓我們可針對這些特殊時機, 執行相關的動作:
40
表單的開始與結束 Load 事件:表單的『載入』事件, 當程式開始執行, 在『顯示表單之前』就會觸發此事件, 所以我們可在此事件中, 進行需在顯示表單前完成的工作。 Shown 事件:當表單第一次顯示在螢幕時, 即會觸發此事件。此事件發生時, 表單『已經』顯示在螢幕上。 FormColsing 事件:當使用者關閉表單時, 就會觸發此事件,此事件會在表單『消失前』發生。 FormClosed 事件:表單已經關閉, 就會觸發此事件, 對一般只有一個表單的應用程式而言, 此事件發生在表單『消失』後、程式結束前所發生的事件
41
表單的開始與結束 我們就用一個計算程式執行時間的範例, 來示範上列事件的應用。
例如我們要以表單從顯示到最後被關閉, 來記算程式執行了多久, 可在表單的Shown事件程序中記錄目前系統時間, 然後在FormClosing事件程序中用當時的系統時間, 減除先前記錄的時間, 即可知道執行了多久。
42
表單的開始與結束 利用Shown及FormClosing 事件程序計算程式執行時間。 建立新專案 Ch10-03, 並在表單中加入一個
控制項。
43
表單的開始與結束 由於我們要在表單載入時記錄系統時間, 但此時間在表單關閉時也要用到, 所以這個變數必須宣告在表單 Form1 類別之內,但在所有程序之外, 我們稱之為『表單變數』。 請切換到程式碼視窗宣告此變數:
44
表單的開始與結束 接著在程式窗格上的下拉式選單選擇 (Form 1 事件), 再選Shown 即可建立其事件程序:
45
表單的開始與結束 在表單的顯示事件中, 要記錄目前的系統時間, 並顯示在表單中:
我們可用上一章介紹過的 DateDiff() 函式計算時間差距,請建立 Form1 的 FormClosing 事件程序, 並輸入如下程式:
46
表單的開始與結束 按[F5] 鍵執行程式, 等幾秒再按 鈕結束程式, 會出現訊息窗顯示程式執行的時間:
47
10-4 滑鼠事件 使用滑鼠操作程式時, 除了按一下滑鼠左鍵產生 Click 事件外, 任何的滑鼠動作, 例如移動滑鼠指標, 都會產生對應的滑鼠事件, 而且有些動作, 其實會產生多個事件。 常見的滑鼠事件有: MouseEnter:滑鼠指標『進入』控制項的區域時所產生的事件。 MouseMove:滑鼠指標在控制項的區域中移動時產生的事件。 MouseLeave:滑鼠指標『離開』控制項的區域時所產生的事件。
48
滑鼠事件 MouseClick:即按一下滑鼠鈕產生的事件, 請注意, 此事件和代表控制項被按一下的 Click 事件不同, 最明顯差異即是 Click事件只有按滑鼠左鈕時才會發生, 但按滑鼠左、中、右鈕, 均會發生 MouseClick 事件。 MouseDoubleClick:雙按滑鼠鈕產生的事件 (雙按中的『第一次』按鈕仍會觸發 MouseClick 事件)。 MouseDown:滑鼠左、中、右鈕被『按下』時產生的事件。MouseUp:滑鼠左、中、右鈕被『放開』時產生的事件。
49
滑鼠事件 前面提到有些滑鼠動作會產生多個事件, 例如在按鈕上按一下, 從按下到放開滑鼠鈕, 前前後後一共會產生 4 個事件(其中按下滑鼠按鈕時會產生第 1 個事件, 放開按鈕時會產生 2~4 事件): MouseDown 事件。 Click 事件 (只有按滑鼠左鈕才會發生此事件)。 MouseClick 事件。 MouseUp 事件。
50
滑鼠事件 通常我們都只會處理 Click 事件 (像是按鈕的 Click 事件), 而不需去理會其它的事件。如果想根據使用者操作滑鼠的動作, 做一些特殊處理, 這時才需用到滑鼠的各項事件。 滑鼠事件程序的第 2 個參數, 提供的資訊包括了滑鼠所在的座標、所按的是哪一個按鈕等資訊。
51
滑鼠事件 為讓讀者瞭解滑鼠動作所觸發的滑鼠事件, 接下來就利用滑鼠事件程序來模擬網頁超連結的動作。平常在瀏覽網頁時, 滑鼠指標指到超連結文字上, 就會變成 的圖案, 移開時又會變成平常的 圖案;而按下超連結文字時則會連到所指的網站。我們將用 控制項當成超連結文字, 並透過 MouseEnter、MouseLeave、MouseClick 等事件程序處理上述動作。
52
滑鼠事件 要變更滑鼠的指標圖案, 可透過表單的 Cursor 屬性。內建的Cursors 類別提供了一組預設的滑鼠指標圖案, 由其中選擇一項並設給 Cursor 屬性, 即可改變滑鼠的指標:
53
滑鼠事件
54
滑鼠事件 透過滑鼠事件, 模擬超連結文字的特效及變更滑鼠指標圖案。 建立專案 Ch10-04, 加入一個 控制項。
55
滑鼠事件 我們要讓滑鼠移到文字上時, 滑鼠指標變成 圖案, 所以建立 Label1 的 MouseEnter 事件程序, 並輸入如下程式 ( 程式中也加上將文字顏色換成紅色的效果):
56
滑鼠事件 滑鼠移開時, 則要恢復滑鼠指標、文字顏色的狀態, 所以請建立 Label1 控制項的 MouseLeave 事件程序, 並輸入下列程式:
57
滑鼠事件 最後是按下超連結文字時, 瀏覽網頁的動作, 此處我們用.Net Framework 的 System.Diagnostics.Process 類別, 來建立代表應用程式的物件。請建立 Label1 的 MouseClick 事件程序 ( 按滑鼠任一個按鈕均會觸發), 並輸入如下程式:
58
滑鼠事件
59
滑鼠事件 按[F5] 執行程式測試其效果:
60
滑鼠事件
61
滑鼠事件 在此要提醒讀者, 前面說過, 不管按滑鼠左、中、右鈕, 都會觸發MouseClick 事件。所以像以上的範例, 當滑鼠移到 Label1 控制項上面、按下滑鼠任一個按鈕, 都會連上指定網站。 我們當然可在MouseClick 事件中限制, 只有按下滑鼠左鈕才要處理, 由事件程序的第 2 個參數 e.Button 屬性, 即可得知使用者按的按鈕為何:
62
滑鼠事件 在 V B 輸入程式的過程中, 即會自動列出 W i n d o w s . F o r m s .MouseButtons 的 Left (左鈕)、Middle (中鈕)、Right (右鈕) 供我們選擇, 不需特別記憶。
63
10-5 鍵盤事件 鍵盤事件就是使用者按下鍵盤按鍵時, 所觸發的各種事件。常見的鍵盤事件包括: KeyDown:按鍵被按下時產生的事件。
KeyPress:和前項有點類似, 但此項是按鍵被按下, 且產生輸入字元時產生的事件。如果單純只按 或 這類不會輸入字元的按鍵, 就不會發生 KeyPress 事件。 KeyUp:按鍵被放開的事件。
64
鍵盤事件 同樣的, 當我們用鍵盤輸入時, 通常會產生多個事件, 例如在TextBox 控制項中輸入一個『A』時, 依序會觸發下列事件:
KeyDown。 KeyPress。 TextChanged。 KeyUp。
65
鍵盤事件 若想得知使用者按什麼按鍵、輸入什麼字元, 可從事件程序的第 2 個參數 e 取得。不過 KeyDown、KeyUp 事件程序的參數, 和KeyPress 的不同, 以下我們先說明 KeyDown、KeyUp 事件程序的參數。
66
KeyDown、KeyUp 事件 在 KeyDown、KeyUp 事件程序中, 第二個參數 e 的下列屬性, 提供使用者按鍵的相關資訊:
KeyCode:使用者所按按鍵的代碼, 可使用 Keys 的各種按鍵名稱來表示, 例如 Keys.A 代表按[A] 鍵、Keys.F1 代表[F1] 鍵、Keys.D0 ~ Keys.D9 代表數字鍵[0] ~[9] , 在編輯程式時, VB會列出 Keys 下的按鍵名稱供我們選擇:
67
KeyDown、KeyUp 事件
68
KeyDown、KeyUp 事件 Modifiers:表示按下 KeyCode 所指按鍵的同時, 是否也按了[Ctrl]、[Shift]、[Alt] 這 3 個特殊按鍵, 其按鍵名稱分別是 Keys.ControlKey、Keys.ShiftKey 、Keys.Alt (均不分左右鍵)。若同時按數個鍵, 則屬性值是數個按鍵名稱以 Or 組合起來, 例如:
69
KeyDown、KeyUp 事件 Shift:表示是否同時按下[Shift] 鍵, 為布林值。
Control:表示是否同時按下[Ctrl] 鍵, 為布林值。 Alt:表示是否同時按下[Alt] 鍵, 為布林值。
70
KeyDown、KeyUp 事件 由於 Modifiers 和 Shift、Control、Alt 都是記錄有無按下特殊按鍵的狀態, 所以用 Modifiers 或另 3 個屬性來判斷都可以, 例如要檢查使用者按下按鍵時, 是否同時按下 [Shift]鍵, 下列兩種寫法的效果相同:
71
KeyDown、KeyUp 事件 為練習鍵盤事件, 我們修改上一章的跑馬燈範例程式, 讓使用者可透過[Ctrl] +[+] 鍵將跑馬燈移動的速度加快、按[Ctrl] +[-] 則可減速。所以我們只需在 KeyDown 事件程序中, 檢查使用者是否按下上述組合鍵, 並將 Timer 的時間間隔減少或增加即可。
72
KeyDown、KeyUp 事件 處理鍵盤事件, 讓使用者可由按鍵控制跑馬燈速度。
建立新專案 Ch10-05, 加入一個 控制項及 控制項。
73
KeyDown、KeyUp 事件 建立表單的 KeyDown 事件程序, 在其中用 If 敘述判斷使用者是否按了[Ctrl] +[+] 或[Ctrl] +[-] 按鍵組合, 是就調整 Timer1控制項的 Interval 屬性 ( 程式中是每次加、減 25 毫秒), 並將新的值顯示在表單標題欄:
74
KeyDown、KeyUp 事件
75
KeyDown、KeyUp 事件 建立 的 Tick 事件程序, 並輸入下列產生跑馬燈效果的程式:
76
KeyDown、KeyUp 事件 按 [F5] 執行程式, 接著即可用[Ctrl] +[+] 和[Ctrl] +[-] 調整跑馬燈速度:
77
KeyPress 事件 如前所述, 如果所按的按鍵不會產生字元輸入, 就不會觸發KeyPress 事件。也因此 KeyPress 事件程序的第 2 個參數, 不會記錄詳細的按鍵資訊, 只會記錄輸入的字元值。KeyPress 事件程序的第 2 個參數 e 有以下兩個屬性: KeyChar:代表輸入的字元, 如果使用中文、日文等輸入法, 此屬性值也會是最後輸入的中文、日文等字元, 而不會是輸入法中用到的按鍵字元 ( 例如用注音輸入法輸入『依』, 則 KeyChar的值會是『依』, 而非鍵盤上代表注音字根的『一』。
78
KeyPress 事件 Handled:此屬性較特別, 它不是供系統傳資料給事件程序用, 而是讓事件程序告訴系統, 是否要繼續處理此字元輸入事件。在正常的運作情況下, 當我們替控制項 (例如 TextBox) 建立處理 KeyPress 的事件程序, 在事件程序執行完畢後, 相同的事件資訊會再送給 TextBox 類別內建的程序繼續處理。但如果我們想在自己處理完畢後, 不要再讓 TextBox 類別繼續處理, 就可將Handled 設為 True, 如此一來 KeyPress 事件的處理工作就算結束, TextBox 類別不會再做處理。
79
KeyPress 事件
80
KeyPress 事件 利用 KeyPress 事件程序, 設計一個當使用者輸入 0~9 的字元時, 自動轉成 “零”~“九” 字元的程式。
81
KeyPress 事件 建立新專案 Ch10-06, 加入 、 控制項。
82
KeyPress 事件 當使用者勾選 選項時, 程式就要將輸入的 0 ~ 9 字元, 自動換成 “ 零” ~ “ 九”。所以請建立 TextBox1 的KeyPress 事件程序, 在使用者勾選 時, 進行轉換工作:
83
KeyPress 事件
84
KeyPress 事件 按[F5] 鍵執行程式, 勾選 時, 即可用數字鍵輸入 " 零" ~ " 九" 的數字。
85
KeyPress 事件 上面的範例是為了示範 e.Handled 的效果, 所以程式中將 e.Handled 設為 True, 讓 TextBox 類別不做後續處理。但如此一來在『啟用漢字數字』時, 也讓文字輸入方塊失去一些編輯功能, 例如輸入游標移到字串中間時, 不能在該處輸入文字、選取一段文字再輸入時, 不能取代被選取的文字。 請試修改 Ch10-06 專案中的程式碼, 讓它仍具有『啟用漢字輸入』的功能, 但也保有TextBox 控制項原有的輸入、編輯功能。
86
KeyPress 事件 將 KeyPress 事件程序改成『只將 e.KeyChar 代換成漢字字元, 但不做其它處理』即可。因為我們的事件程序結束後, 控制項本身會再做後續處理, 所以這時它看到的 e.KeyChar 變成漢字字元, 就會依其內建功能, 加入該字元、或用該字元取代被選取的文字等。
87
KeyPress 事件
Similar presentations