-1

在一个应用程序上,我有一个键盘钩子,当按下 Escape 按钮时,它会关闭一个 MDI 子窗体。打开 TOpenDialog 类后代时出现问题(使用Execute)。考虑以下代码(仅用于示例)

unit Unit4;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm4 = class(TForm)
    OpenDialog1: TOpenDialog;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

function KeyboardProc(code: integer; wp: WPARAM; lp: LPARAM): LResult stdcall;
function CanDoCloseOnEscape: boolean;

var
  Form4: TForm4;
  KeybHook : HHook;


implementation

{$R *.dfm}

function CanDoCloseOnEscape: boolean;
var
  Control: TWinControl;
  Form: TForm;
begin
  Control := Screen.ActiveControl;
  Form := Screen.ActiveForm;
  Result := true;
end;

function KeyboardProc(code: integer; wp: WPARAM; lp: LPARAM): LResult stdcall;
begin
  case wp of
    VK_ESCAPE:
      if CanDoCloseOnEscape then
      begin
        PostMessage(Screen.ActiveForm.Handle, WM_Close, 0, 0);
        exit;
      end;
  end;
end;

procedure TForm4.Button1Click(Sender: TObject);
begin
 if OpenDialog1.Execute then
  begin
    ShowMessage('executed');
  end;
end;

initialization
  KeybHook := SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, hInstance,GetWindowTask(application.Handle));

finalization
  UnhookWindowsHookEx(KeybHook);

end.

控制 := Screen.ActiveControl;

  • 没有将 opendialog 作为主动控件。

因此,即使对话框仍然打开,也会执行键盘挂钩并关闭表单。

4

1 回答 1

6

根本问题是您正在(ab)使用键盘挂钩。这是一个全局事件,您需要检测更多本地键盘事件。你应该安排你的 Delphi 表单来监听ESC被按下的键。

在我的脑海中,我不确定 MDI 表单或 MDI 子项是否会收到该事件,但无论是哪一个,您都需要在那里处理它。您可能需要设置KeyPreviewTrue使其正常工作。

更笼统地说,如果要采用全局方法,键盘钩子仍然是错误的工具。您将使用的工具将是对象的OnMessage事件Application。这被连接到应用程序的主消息队列中,并且任何 Delphi 模式消息泵都从ShowModal调用中运行。在那里进行处理意味着您将检测到用于 VCL 表单的键盘事件,但您不会为非 VCL 模态​​窗口(如文件对话框、Win32 消息框等)拾取键盘事件。

于 2013-09-03T13:55:35.323 回答