Delphi 如何在编辑框中接收TAB键?
我想在用户按下Tab键时接收Delphi 如何在编辑框中接收TAB键?,delphi,accessibility,subclassing,delphi-5,Delphi,Accessibility,Subclassing,Delphi 5,我想在用户按下Tab键时接收OnKeyPress事件 我尝试对Edit框进行子类化,并处理WM_GETDLGCODE消息: procedure TfrmEnableVIPMode.AccountNumberWindowProc(var Message: TMessage); begin case Message.Msg of WM_GETDLGCODE: Message.Result := DLGC_WANTTAB; else FOldAccountNumberWi
OnKeyPress
事件
我尝试对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;
procedure TfrmEnableVIPMode.AccountNumberWindowProc(var Message: TMessage);
begin
case Message.Msg of
CN_KEYDOWN:
if TWMKey(Message).CharCode = VK_TAB then
....
end;
FOldAccountNumberWindowProc(Message);
end;
现在我接收到TabKeyPress事件(正如我所希望的那样),但现在按向左或向右光标键会使焦点转移到Tab顺序中的上一个或下一个控件
接收Tab键的正确方式是什么
额外阅读
我试着按照MSDN文档所说的做:
wParam用户按下的虚拟键,提示Windows 发布此通知。处理程序必须有选择地处理这些问题 钥匙。例如,处理程序可能接受并处理VK_返回,但是 将VK_选项卡委托给所有者窗口。有关值列表,请参见 虚拟密钥代码 lParam指向消息结构的指针(如果 系统正在执行查询) 但是
wParam
和wParam
都是零
更新二
我意识到我也有同样的想法:
当我实际使用同一答案中其他地方列出的正确代码中的概念时:
if Assigned(FOldWndProc) then FOldWndProc(Message);
if Message.Msg = WM_GETDLGCODE then
Message.Result:= Message.Result or DLGC_WANTTAB;
这有助于解释为什么我的原始代码是错误的。将Message.Result
设置为DLGC\u WANTTAB
错误:
procedure TfrmEnableVIPMode.AccountNumberWindowProc(var Message: TMessage);
begin
case Message.Msg of
WM_GETDLGCODE: Message.Result := DLGC_WANTTAB;
else
FOldAccountNumberWindowProc(Message);
end;
end;
尝试将标志DLGC\u 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的EDIT
control设置Message.Result的正确值然后我可以按位组合DLGC\u 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标志
所以这更好。光标键继续在编辑控件中导航文本(而不是移动焦点),我会收到选项卡键的OnKeyPress
(和onkeypdown
和onkeypup
)事件
剩下的问题是用户按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键
花言巧语
您可以处理CN\u向下键
消息:
procedure TfrmEnableVIPMode.AccountNumberWindowProc(var Message: TMessage);
begin
case Message.Msg of
WM_GETDLGCODE: Message.Result := DLGC_WANTTAB;
else
FOldAccountNumberWindowProc(Message);
end;
end;
procedure TfrmEnableVIPMode.AccountNumberWindowProc(var Message: TMessage);
begin
case Message.Msg of
CN_KEYDOWN:
if TWMKey(Message).CharCode = VK_TAB then
....
end;
FOldAccountNumberWindowProc(Message);
end;
也可以在表单级别检测按键关闭消息,而无需将编辑子类化:
procedure TfrmEnableVIPMode.CMDialogKey(var Message: TCMDialogKey);
begin
if (Message.CharCode = VK_TAB) and (ActiveControl = edAccountNumber) then
...
inherited;
end;
您需要首先调用上一个WndProc,以便消息.Result为TEdit
本机需要的键代码获取默认值,然后将您的DLGC\u WANTTAB
标志附加到该结果,例如:
procedure TfrmEnableVIPMode.AccountNumberWindowProc(var Message: TMessage);
begin
FOldAccountNumberWindowProc(Message);
if Message.Msg = WM_GETDLGCODE then
Message.Result := Message.Result or DLGC_WANTTAB;
end;
你可能会从中得到灵感。@TLama它确实帮助我在我使用的方法中发现了一个(常见的)错误。我可能使用了完全错误的方法,但至少我修复了错误的方法!首先你说“我想让编辑控件获得制表键而不是移动焦点”,然后你抱怨“编辑控件获得制表键而不是移动焦点!”你想要哪一个?+1详细说明,但值得通读。@RaymondChen这些是Delphi表单;不是真正的Windows“对话框”。也许这与意外行为有关。