Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 如何在编辑框中接收TAB键?_Delphi_Accessibility_Subclassing_Delphi 5 - Fatal编程技术网

Delphi 如何在编辑框中接收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

我想在用户按下Tab键时接收
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“对话框”。也许这与意外行为有关。