【问题标题】:How to capture KeyDown when focused controls interfere?当焦点控件干扰时如何捕获 KeyDown?
【发布时间】:2021-05-20 15:05:36
【问题描述】:

我有一个 KeyPreview=true 的表单并且想要捕获箭头键,除非我们在一个应该处理这些的控件中。 问题是:焦点总是在其中一个控件上。

我怎样才能适应/设计它来工作?

.PAS 文件

unit uKeyDownTests;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;

type
  TFrmKeyDownTests = class(TForm)
    PnlBottom: TPanel;
    PnlClient: TPanel;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  private
  public
  end;

var
  FrmKeyDownTests: TFrmKeyDownTests;

implementation

{$R *.dfm}

type
  THackWinControl = class(TWinControl);

procedure TFrmKeyDownTests.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
var lActiveControl: TControl;
begin
   // Earlier code, but that did not work either:
   // if Edit1.Focused or Edit2.Focused or Edit3.Focused then Exit;

   lActiveControl := ActiveControl;
   if Assigned(lActiveControl) then
   begin
      if lActiveControl = Edit1 then
      begin
          THackWinControl(Edit1).KeyDown(Key,Shift);
          Exit;
      end;
      if lActiveControl = Edit2 then
      begin
          THackWinControl(Edit2).KeyDown(Key,Shift);
          Exit;
      end;
      if lActiveControl = Edit3 then
      begin
          THackWinControl(Edit3).KeyDown(Key,Shift);
          Exit;
      end;
   end;

   if (Key = VK_RIGHT) then
   begin
      PnlBottom.Caption := PnlBottom.Caption + 'R';
      Key := 0;
      Exit;
   end;
   if (Key = VK_LEFT) then
   begin
      PnlBottom.Caption := PnlBottom.Caption + 'L';
      Key := 0;
      Exit;
   end;
   if (Key = VK_UP) then
   begin
      PnlBottom.Caption := PnlBottom.Caption + 'U';
      Key := 0;
      Exit;
   end;
   if (Key = VK_DOWN) then
   begin
      PnlBottom.Caption := PnlBottom.Caption + 'D';
      Key := 0;
      Exit;
   end;
end;

end.

.DFM 文件

object FrmKeyDownTests: TFrmKeyDownTests
  Left = 0
  Top = 0
  Caption = 'Keydown tests'
  ClientHeight = 336
  ClientWidth = 635
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  KeyPreview = True
  OldCreateOrder = False
  OnKeyDown = FormKeyDown
  PixelsPerInch = 96
  TextHeight = 13
  object PnlBottom: TPanel
    Left = 0
    Top = 295
    Width = 635
    Height = 41
    Align = alBottom
    TabOrder = 0
  end
  object PnlClient: TPanel
    Left = 0
    Top = 0
    Width = 635
    Height = 295
    Align = alClient
    TabOrder = 1
    object Edit1: TEdit
      Left = 40
      Top = 32
      Width = 121
      Height = 21
      TabOrder = 0
      Text = 'Edit1'
    end
    object Edit2: TEdit
      Left = 40
      Top = 72
      Width = 121
      Height = 21
      TabOrder = 1
      Text = 'Edit1'
    end
    object Edit3: TEdit
      Left = 40
      Top = 112
      Width = 121
      Height = 21
      TabOrder = 2
      Text = 'Edit1'
    end
  end
end

【问题讨论】:

  • 尝试使用 KeyboardHook。
  • 您不需要手动调用ActiveControl.KeyDown()。如果您有KeyPreview=True 并且Form 的OnKey... 处理程序未设置Key=0,则首先将密钥传递给Form 的控件将在Form 的OnKey... 处理程序退出后正常完成对密钥的处理。您应该阅读 Peter 下面关于 A Key’s Odyssey 的文章,它解释了 VCL 如何处理击键,以及公开了哪些钩子供您进行自定义处理。

标签: delphi focus keydown delphi-10.4.2


【解决方案1】:

(根据我的具体情况回答我自己的问题,与“可能的骗子”中的问题略有不同,但基于那里的答案)
就我而言,最简单的解决方案是:

  • procedure DialogKey(var Msg: TWMKey); message CM_DIALOGKEY; 仅调用继承
  • KeyPreview=true 表格
  • FormKeydown 处理我想用箭头键做的事情

结果:

  • 具有焦点的控件以及表单处理箭头键
  • 控件是否具有 OnKeyDown 处理程序(Edit2 控件)无关紧要(其他)

修改代码:

unit uKeyDownTests;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;

type
  TFrmKeyDownTests = class(TForm)
    PnlBottom: TPanel;
    PnlClient: TPanel;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure Edit2KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  private
    procedure DialogKey(var Msg: TWMKey); message CM_DIALOGKEY;  public
  end;

var
  FrmKeyDownTests: TFrmKeyDownTests;

implementation

{$R *.dfm}

procedure TFrmKeyDownTests.DialogKey(var Msg: TWMKey);
begin
   inherited;
end;

procedure TFrmKeyDownTests.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
   case Key of
      VK_RIGHT: PnlBottom.Caption := PnlBottom.Caption + 'R';
      VK_LEFT : PnlBottom.Caption := PnlBottom.Caption + 'L';
      VK_UP   : PnlBottom.Caption := PnlBottom.Caption + 'U';
      VK_DOWN : PnlBottom.Caption := PnlBottom.Caption + 'D';
   end;
end;


{ TFrmKeyDownTests }

procedure TFrmKeyDownTests.Edit2KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
   PnlBottom.Caption := PnlBottom.Caption + '-kd-';
end;

end.

【讨论】:

    猜你喜欢
    • 2018-11-24
    • 1970-01-01
    • 2015-10-14
    • 1970-01-01
    • 2015-05-21
    • 2015-01-01
    • 1970-01-01
    • 2012-08-24
    • 1970-01-01
    相关资源
    最近更新 更多