詳解C#鼠標(biāo)事件的處理機(jī)制
過去用C++/MFC開發(fā)程序時,常常為用戶提供鼠標(biāo)的右鍵單擊功能,如今在.NET框架中使用C#,也想在程序中提供鼠標(biāo)右鍵單擊功能,比如,在文本框、窗格、標(biāo)簽以及主窗口背景上使用鼠標(biāo)右鍵。畢竟C#不是C++/MFC,那么如何處理C#鼠標(biāo)事件呢?本文下面將專門探討這個問題。
在.NET框架下編程是非常容易的一件事情,有時候容易得連C++程序員想都想不到。這主要是因?yàn)橛肅++編寫代碼常常需要“硬工夫”。所謂“硬工夫”,也就是很多細(xì)節(jié)都要自己考慮和處理。但使用C#則不然。如果你想顯示上下文菜單,完全沒有必要去和事件參合。只要設(shè)置控制的ContextMenu屬性即可,就象下面這樣:
- ContextMenu myContextMenu = ...
- myControl.ContextMenu = myContextMenu;
就這么簡單。只要按照上述方法設(shè)置好屬性,當(dāng)用戶單擊右鍵時,菜單便會自動顯示出來。此外,如果你想進(jìn)一步實(shí)現(xiàn)右鍵拖拽,這才涉及到事件處理。在MFC中,你會自然而然想到用OnRButtonDown和OnRButtonUp實(shí)現(xiàn),但是那不是Windows窗體(Forms)的工作方式。雖然許多窗口類確實(shí)提供了可以改寫的虛擬函數(shù)來處理常用消息(如:Form.OnActivated和Form.OnClosed),但是在.NET框架中編程,你必須要學(xué)會用事件來思考,而且要了解一個類提供了哪些事件。下面這個表列出了被Control類提供的比較常用的事件:
(表一)
Click | HelpRequested | MouseLeave |
ContextMenuChanged | Invalidated | MouseMove |
DoubleClick | KeyDown | MouseUp |
DragDrop | KeyPress | MouseWheel |
DragEnter | KeyUp | Move |
DragLeave | Layout | Paint |
DragOver | Leave | ParentChanged |
EnabledChanged | LostFocus | Resize |
Enter | MouseDown | SizeChanged |
FontChanged | MouseEnter | StyleChanged |
GotFocus | MouseHover | TextChanged |
注意表中用黑體標(biāo)出的事件,這些事件顧名便可思意:MouseDown、 MouseEnter、 MouseHover、 MouseLeave、 MouseMove 和 MouseUp,如果你想要處理右鍵按下事件,可以安裝MouseDown 事件處理例程,用MouseEventArgs.Button == MouseButtons.Right 檢查 MouseEventArgs,下面的代碼段示范了如何來做:
- public class MyControl : Control
- {
- // 構(gòu)造函數(shù)
- public MyControl() {
- // 安裝右鍵按下事件處理器
- this.myctl1.MouseDown +=
- new MouseEventHandler(this.OnMouseDown);
- }
- // 處理例程
- private void OnMouseDown(object sender, MouseEventArgs e) {
- if (e==MouseButtons.Right)
- // do something
- }
- }
表一里有三個有用的鼠標(biāo)事件是在MFC中不能直接處理的:MouseEnter、 MouseHover 和MouseLeave。在Win32 里,要處理這些事件必須通過專門的TrackMouseEvent 函數(shù)。.NET框架中,每當(dāng)鼠標(biāo)進(jìn)入或離開特定控制時便會觸發(fā)MouseEnter 和MouseLeave,當(dāng)你想在鼠標(biāo)移動到控制上時使控制呈高亮狀態(tài),這些事件相當(dāng)有用,例如在瀏覽器中高亮顯示鏈接。當(dāng)鼠標(biāo)移動到控制上后,在預(yù)先確定好的時間里(這個時間由 SystemParametersInfo(SPI_GETMOUSEHOVERTIME)) 指定),.NET 框架會激活 MouseHover。它在 Tooltips 和其它類似的定時彈出式功能應(yīng)用中廣泛使用。
這些鼠標(biāo)事件和大家所熟悉的Click 事件有何關(guān)系呢?我想可以這么認(rèn)為,Click屬于層次較高的邏輯事件,而鼠標(biāo)事件的級別相對較低,例如,不管用戶按下的是左鍵還是右鍵,F(xiàn)orms都觸發(fā)Click 事件,而文本框只能觸發(fā)左鍵的Click事件。表二中列出了不同種類的控制其Click事件的含意。
(表二)由 Click 激發(fā)的事件
控制或控件 | 鼠標(biāo)左鍵單擊 | 鼠標(biāo)左鍵雙擊 | 鼠標(biāo)右鍵單擊 | 鼠標(biāo)右鍵雙擊 | 鼠標(biāo)中鍵單擊 | 鼠標(biāo)中鍵雙擊 |
---|---|---|---|---|---|---|
MonthCalendar, DateTimePicker, RichTextBox, HScrollBar, VScrollBar | None | None | None | None | None | None |
Button, CheckBox, RadioButton | Click | Click, Click | None | None | None | None |
ListBox, CheckedListBox, ComboBox | Click | Click, DoubleClick | None | None | None | None |
TextBox, DomainUpDown, NumericUpDown | Click | Click, DoubleClick | None | None | None | None |
*TreeView, *ListView | Click | Click, DoubleClick | Click | Click, DoubleClick | None | None |
ProgressBar TrackBar | Click | Click, Click | Click | Click, Click | Click | Click, Click |
Form, DataGrid, Label, LinkLabel, Panel,GroupBox, PictureBox, Splitter, DoubleClick, StatusBar,ToolBar, TabPage, **TabControl | Click | Click, DoubleClick | Click | Click, DoubleClick | Click | Click, DoubleClick |
* 鼠標(biāo)指針必須在子對象上方 (TreeNode 或 ListViewItem) ** TabControl 必須在其 TabPages 頁集合中至少有一個 TabPage。 |
***,不管怎樣,只要你愿意,總是可以改寫Control.WndProc 來處理任何WM_XXX 消息,比如:你可以定制WM_NCLBUTTONDOWN 消息處理代碼:
- protected override void WndProc(ref Message m)
- {
- // 值來自 winuser.h
- const int WM_NCLBUTTONDOWN = 0x00A1;
- if (m.Msg == WM_NCLBUTTONDOWN) {
- //do something
- }
- base.WndProc(ref m); // 這一步不能忘!
- }
我寫了一個例子程序MouseTrap,如圖一所示,
圖一 MouseEventTrap
該程序示范了如何進(jìn)行鼠標(biāo)事件的處理。如果你借WndProc處理消息,由于必須用IntPtrs獲取消息參數(shù),所以你或多或少要用C編程,但因?yàn)槟阋呀?jīng)諳熟C++,所以此時你不會感覺吃力,而是輕車熟路。