在 TComboBox 或 TButton 上按 VK_LEFT 键时,OnKeyDown 事件未触发

5

有没有办法在按下TCheckBox或TButton控件上的VK_LEFT键时触发OnKeyDown事件。目前,它只是选择另一个控件,但不会触发该事件。

更新

这是我使用VK_LEFT键像TAB Back一样的代码。

首先,我需要禁用某些控件(如TCheckBox、TButton等)上VK_LEFT的标准行为:

procedure TfmBase.CMDialogKey(var Message: TCMDialogKey);
begin
  if Message.CharCode <> VK_LEFT then
    inherited;
end;

然后,在TCheckBox、TButton等控件上,VK_LEFT键也会触发OnKeyDown事件。在该事件中,我编写了代码以选择前一个控件。当然,KeyPreview必须为true。

procedure TfmBase.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
var
  handled: Boolean;
begin
  if Key = VK_LEFT then
  begin
    handled := false;
    TabBack(handled); //This is my function, which checks the type of the control and selects the previous control.
    if handled then
      Key := 0;
  end;
end;
2个回答

5
您无法触发该事件,因为该按键被解释为表单导航。顶层消息循环识别到这是一个导航键,并将消息重定向以执行该导航。
如果您想处理此事件,则唯一的机会是在 Application.OnMessage 中进行,该事件在消息被重定向之前触发。
更新:
在评论中,您指出要拦截此事件以执行导航。由于默认导航正在执行,因此未触发该事件,也许理想的解决方案是覆盖默认导航。
我认为驱动此过程的关键程序是 TWinControl.CNKeyDown。通过阅读这段代码,我认为您只需要在您的表单中处理 CM_DIALOGKEY 并说服导航按您所需的方式行事即可。
您的代码应该类似于这样:
procedure TMyForm.CMDialogKey(var Message: TCMDialogKey);
begin
  if GetKeyState(VK_MENU) >= 0 then begin
    case Message.CharCode of
    VK_LEFT:
      if ActiveControl=MyControl1 then begin
        MyControl2.SetFocus;
        Message.Result := 1;
        Exit;
      end;
    end;
  end;
  inherited;
end;

谢谢。实际上,我也想将该键用于表单导航,但是当这样的控件放置在嵌套面板中(例如TFlowPanel->TPanel)时,TPanels之间的导航不起作用。因此,我实际上想将其用作TAB(返回)。 - markus_ja
@Sertac 按照您的建议处理 CM_CHILDKEY 会绕过 CM_DIALOGKEY 的效果。但是,您需要在控件中处理它而不是表单。这肯定是可能的。然而,由于 @max 想要进行导航,我认为 CM_DIALOGKEY 没有更好的解决方案。您同意吗? - David Heffernan
@max 啊,那不是我想表达的意思。只有当它匹配你感兴趣的键和控件时,你才需要将 Msg.Result 设置为0。否则,你会破坏整个表单的导航。此外,CMDialogKey 是为了让你在那里进行导航而设计的。你只需要调用 SetFocus 来设置你想要导航到的控件。按照这种方式做,根本不需要处理 KeyDown! - David Heffernan
@David - CM_CHILDKEY是在表单上执行的,这就是为什么该消息具有'Sender'成员的原因。不知道,只要它能工作,我就看不出有什么区别。 :) - Sertac Akyuz
@Sertac 在我查看的 VCL 源代码中,我只能看到它在 TWinControl 上执行。 - David Heffernan
显示剩余11条评论

4

您需要处理WM_GETDLGCODE消息:

procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
....
procedure TfmBase.WMGetDlgCode(var Message: TWMGetDlgCode);
 begin
   Message.Result:=DLGC_WANTALLKEYS or DLGC_WANTARROWS;
 end;

我在拦截TCheckBox的KeyDown事件时遇到了同样的问题,你的提示对我非常有用。非常感谢。 - Delphiman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接