轉帖|其它|編輯:郝浩|2010-12-01 16:05:21.000|閱讀 665 次
概述:本問主要介紹如何讓ToolBox控件響應鍵盤操作,希望對大家有幫助。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
最近,一朋友問我如何讓ToolBox控件也能響應鍵盤操作,也就是用Up,down按鍵來選擇工具箱控件里的Item,他添加了鍵盤事件,但是不起作用。一開始做這個控件的時候也只是演示一下控件的制作過程,只用了很短的時間做了一個,只考慮了用鼠標選取,沒有考慮鍵盤操作,我想要添加鍵盤操作無非重載KeyDown事件,針對Up,Down做一些響應就可以了。可是添加了重載了OnKeyDown事件后,結果和那位朋友所說的一樣,沒有任何作用,我設了斷點,調試了一下,發現KeyDown根本捕獲不到Up,Down按鍵的點擊,是什么原因呢,是不是忘記設控件的風格以便讓它能夠獲得焦點?于是,我使用了語句:
SetStyle(ControlStyles.Selectable, true);
依然沒有效果,當我們在控件上按下Down鍵的時候,另一個控件獲得了焦點。這時Up,Down按鈕只是起到了導航的作用就像Tab鍵一樣。
接下來,我在測試工程的窗體上放置了一個ListBox控件做一個對比,其實ToolBox和ListBox在界面表現上有相似之處,就是都有子Item,并且在ListBox上點擊Down是起作用的,ListBox并沒有失去焦點,這說明這時Up,Down按鍵沒有成為導航鍵。我想Windows一定是對默認的導航鍵Up,Down,Left,Right有默認的處理,除非你希望你的控件希望自己處理這些鍵。用反匯編工具看了一下ListBoxControl控件的源代碼,發現一個有趣的函數:
protected override bool IsInputKey(Keys keyData)
{
if ((keyData & Keys.Alt) == Keys.Alt)
{
return false;
}
switch ((keyData & Keys.KeyCode))
{
case Keys.Prior:
case Keys.Next:
case Keys.End:
case Keys.Home:
return true;
}
return base.IsInputKey(keyData);
}
在這里面,ListBoxControl允許Prior,Next,End,Home成為有效的輸入鍵,接著一路跟下去,看看winform控件的基類Control的這個函數是如何處理的:
[UIPermission(SecurityAction.InheritanceDemand, Window=UIPermissionWindow.AllWindows)]
protected virtual bool IsInputKey(Keys keyData)
{
if ((keyData & Keys.Alt) != Keys.Alt)
{
int num = 4;
switch ((keyData & Keys.KeyCode))
{
case Keys.Left:
case Keys.Up:
case Keys.Right:
case Keys.Down:
num = 5;
break;
case Keys.Tab:
num = 6;
break;
}
if (this.IsHandleCreated)
{
return ((((int) this.SendMessage(0x87, 0, 0)) & num) != 0);
}
}
return false;
}
注意這一行return ((((int) this.SendMessage(0x87, 0, 0)) & num) != 0);0x87是什么windows消息呢,打開WinUser.h文件,發現是WM_GETDLGCODE,在MSDN中的描述是這樣的:
The WM_GETDLGCODE message is sent to the window procedure associated with a control. By default, the system handles all keyboard input to the control; the system interprets certain types of keyboard input as dialog box navigation keys. To override this default behavior, the control can respond to the WM_GETDLGCODE message to indicate the types of input it wants to process itself.
也就是說windows用這個消息來判斷哪些類型的輸入交給控件本身來處理。然后,我注意到,對于方向導航鍵,函數都給于一個值5與this.SendMessage(0x87, 0, 0))的返回值進行與操作,那么this.SendMessage(0x87, 0, 0))的返回值都可能是什么值呢,WinUser.h中是這樣聲明的:
/*
* Dialog Codes
*/
#define DLGC_WANTARROWS 0x0001 /* Control wants arrow keys */
#define DLGC_WANTTAB 0x0002 /* Control wants tab keys */
#define DLGC_WANTALLKEYS 0x0004 /* Control wants all keys */
#define DLGC_WANTMESSAGE 0x0004 /* Pass message to control */
#define DLGC_HASSETSEL 0x0008 /* Understands EM_SETSEL message */
#define DLGC_DEFPUSHBUTTON 0x0010 /* Default pushbutton */
#define DLGC_UNDEFPUSHBUTTON 0x0020 /* Non-default pushbutton */
#define DLGC_RADIOBUTTON 0x0040 /* Radio button */
#define DLGC_WANTCHARS 0x0080 /* Want WM_CHAR messages */
#define DLGC_STATIC 0x0100 /* Static item: don't include */
#define DLGC_BUTTON 0x2000 /* Button item: can be checked */
5最貼切的表達就是DLGC_WANTMESSAGE | DLGC_WANTARROWS,也就是將方向鍵發送給控件處理,對于6呢,也就是DLGC_WANTMESSAGE| DLGC_WANTTAB,將Tab鍵發送給控件處理。
從這段代碼里和控件實際的行為我們可以得出一個結論,那就是,控件本身是不處理方向鍵和Tab鍵的,因為他們有默認的行為,也就是支持焦點在窗體的控件之間轉換。如果你想要處理這些導航鍵,那么結論很簡單,就是重載IsInputKey方法,它是一個保護類型的虛方法。
在ToolBox控件的代碼里重載IsinputKey方法:
protected override bool IsInputKey(Keys keyData)
{
if ((keyData & Keys.Alt) == Keys.Alt)
{
return false;
}
switch ((keyData & Keys.KeyCode))
{
case Keys.Up:
case Keys.Down:
return true;
}
return base.IsInputKey(keyData);
}
當用戶點擊的鍵是Up,Down的時候,返回true,這時我們的OnKeyDown方法里就可以捕獲到Up,Down的點擊事件了。
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉載自:博客轉載