How to receive TAB key press in edit box?
我希望在用户按下Tab键时接收
1 2 3 4 5 6 7 8 9 | procedure TForm1.Edit1(Sender: TObject; var Key: Char); begin case Key of #09: begin //Snip - Stuff i want to do end; end; end; |
我尝试对
1 2 3 4 5 6 7 8 | procedure TfrmEnableVIPMode.AccountNumberWindowProc(var Message: TMessage); begin case Message.Msg of WM_GETDLGCODE: Message.Result := DLGC_WANTTAB; else FOldAccountNumberWindowProc(Message); end; end; |
现在我收到Tab KeyPress事件(如我希望的那样),但是现在按下Left或Right光标键会导致焦点转移到制表符顺序中的上一个或下一个控件。
接收Tab键按下事件的正确方法是什么?
奖励阅读
我尝试执行MSDN文档所说的内容:
wParam
The virtual key, pressed by the user, that prompted Windows to
issue this notification. The handler must selectively handle these
keys. For instance, the handler might accept and process VK_RETURN but
delegate VK_TAB to the owner window. For a list of values, see
Virtual-Key Codes.lParam A pointer to an MSG structure (or NULL if
the system is performing a query).
但
更新二
我意识到我和这个答案有相同的错误:
1 2 3 4 | if Message.Msg = WM_GETDLGCODE then Message.Result:= Message.Result or DLGC_WANTTAB else if Assigned(FOldWndProc) then FOldWndProc(Message); |
当我实际上应该使用相同答案中其他位置列出的正确代码中的概念时:
1 2 3 | if Assigned(FOldWndProc) then FOldWndProc(Message); if Message.Msg = WM_GETDLGCODE then Message.Result:= Message.Result or DLGC_WANTTAB; |
这有助于解释为什么我的原始代码是错误的。将
1 2 3 4 5 6 7 8 | procedure TfrmEnableVIPMode.AccountNumberWindowProc(var Message: TMessage); begin case Message.Msg of WM_GETDLGCODE: Message.Result := DLGC_WANTTAB; else FOldAccountNumberWindowProc(Message); end; end; |
尝试将
1 2 3 4 5 6 7 8 | procedure TfrmEnableVIPMode.AccountNumberWindowProc(var Message: TMessage); begin case Message.Msg of WM_GETDLGCODE: Message.Result := Message.Result or DLGC_WANTTAB; else FOldAccountNumberWindowProc(Message); end; end; |
我必须首先调用原始的窗口过程,以使Windows的
1 2 3 4 5 6 7 8 | procedure TfrmEnableVIPMode.AccountNumberWindowProc(var Message: TMessage); begin FOldAccountNumberWindowProc(Message); case Message.Msg of WM_GETDLGCODE: Message.Result := Message.Result or DLGC_WANTTAB; end; end; |
释义Raymond Chen博客条目,并根据需要添加重点:
After asking the original control what behavior it thinks it wants, we turn on the DLGC_WANTTAB flag
所以这更好。光标键继续在Edit控件中导航文本(而不是移动焦点),并且我收到Tab键的
剩下的问题是用户按下Tab不再转移焦点。
我试图开始着手手动黑客,以改变自己的注意力:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | procedure TfrmEnableVIPMode.edAccountNumberKeyPress(Sender: TObject; var Key: Char); begin case Key of #09: begin //Snip - Stuff i want to do { The DLGC_WANTTAB technique broke Windows focus change. Keep throwing in hacks until it's no longer obviously broken } //Perform(CM_DialogKey, VK_TAB, 0); //doesn't work Self.ActiveControl := Self.FindNextControl(edAccountNumber, True, True, False); end; end; end; |
上面的代码有效-如果用户按下Tab键。但正如Raymond Chen六年前指出的那样,代码已损坏:
There are many things wrong with this approach. You can spend quite a lot of time nitpicking the little details, how this code fails to set focus in a dialog box properly, how it fails to take nested dialogs into account, how it fails to handle the Shift+Tab navigation key
在我的情况下,我破坏了Shift Tab。还有谁知道呢。
所以,我的问题是:
How to receive TAB key press in edit box?
我不想吃它们,我只想知道用户按下了Tab键。
额外的ter不休
- 雷蒙德·陈(Raymond Chen)提供了解决方案,但没有解释为什么它不起作用
- MSDN:WM_GETDLGCODE消息
您可以处理
1 2 3 4 5 6 7 8 9 | procedure TfrmEnableVIPMode.AccountNumberWindowProc(var Message: TMessage); begin case Message.Msg of CN_KEYDOWN: if TWMKey(Message).CharCode = VK_TAB then .... end; FOldAccountNumberWindowProc(Message); end; |
还可以在窗体级别检测按键消息,而无需将编辑归类:
1 2 3 4 5 6 7 | procedure TfrmEnableVIPMode.CMDialogKey(var Message: TCMDialogKey); begin if (Message.CharCode = VK_TAB) and (ActiveControl = edAccountNumber) then ... inherited; end; |
您需要首先调用上一个WndProc,以便Message.Result获取
1 2 3 4 5 6 | procedure TfrmEnableVIPMode.AccountNumberWindowProc(var Message: TMessage); begin FOldAccountNumberWindowProc(Message); if Message.Msg = WM_GETDLGCODE then Message.Result := Message.Result or DLGC_WANTTAB; end; |