当用户按下 Tab 键时,我希望能够接收到 OnKeyPress
事件。
procedure TForm1.Edit1(Sender: TObject; var Key: Char);
begin
case Key of
#09:
begin
//Snip - Stuff i want to do
end;
end;
end;
我尝试对Edit
框进行子类化,并处理WM_GETDLGCODE
消息:
procedure TfrmEnableVIPMode.AccountNumberWindowProc(var Message: TMessage);
begin
case Message.Msg of
WM_GETDLGCODE: Message.Result := DLGC_WANTTAB;
else
FOldAccountNumberWindowProc(Message);
end;
end;
现在我可以接收Tab KeyPress事件了(正如我的希望),但按下左或右光标键会导致焦点转移到制表顺序中的前一个或下一个控件。
接收Tab键Press事件的正确方法是什么?
额外阅读
我尝试按照MSDN文档所说的做:
wParam
用户按下的虚拟键,促使Windows发出此通知。 处理程序必须有选择地处理这些键。例如,处理程序可能接受并处理VK_RETURN,但将VK_TAB委派给所有者窗口。有关值列表,请参见虚拟键代码。lParam指向MSG结构的指针(如果系统正在执行查询,则为NULL)。
但wParam
和wParam
都为零。
更新二
我意识到我有与此答案相同的错误:
if Message.Msg = WM_GETDLGCODE then
Message.Result:= Message.Result or DLGC_WANTTAB
else
if Assigned(FOldWndProc) then FOldWndProc(Message);
在同一个回答中,我应该什么时候使用正确代码中的概念:
if Assigned(FOldWndProc) then FOldWndProc(Message);
if Message.Msg = WM_GETDLGCODE then
Message.Result:= Message.Result or DLGC_WANTTAB;
这有助于解释为什么我的原始代码是错误的。将
Message.Result
设置为DLGC_WANTTAB
是错误的:procedure TfrmEnableVIPMode.AccountNumberWindowProc(var Message: TMessage);
begin
case Message.Msg of
WM_GETDLGCODE: Message.Result := DLGC_WANTTAB;
else
FOldAccountNumberWindowProc(Message);
end;
end;
试图对标志DLGC_WANTTAB
进行位或操作并将其合并到Message.Result
中也是错误的,因为Message.Result
尚未具有值:
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的编辑
控件设置正确的Message.Result
值。 然后我可以按位组合DLGC_WANTTAB
:
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的博客文章,我们需要询问原始控件其所需的行为,并启用DLGC_WANTTAB标志。这样做更好。光标键可继续在编辑控件中导航文本(而不是转移焦点),并且我会收到Tab键的OnKeyPress(以及OnKeyDown和OnKeyUp)事件。
剩余的问题是用户按下Tab键不再转移焦点。
我尝试着手动修改焦点转移,但是遇到了困难。
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 六年前所指出的那样:
在我的情况下,我破坏了 Shift+Tab。还有谁知道其他什么。这种方法有很多问题。你可以花费相当长的时间来挑剔小细节,比如这个代码无法正确设置对话框中的焦点,无法考虑嵌套对话框,无法处理 Shift+Tab 导航键。
因此,我的问题是:
我不想 吃掉 它们,我只想 知道 用户按下了 Tab 键。如何在编辑框中接收 TAB 键按下事件?
这篇帖子
中获得灵感。 - TLama