Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.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 TMemo是如何吃掉一把逃生钥匙的,而TEdit没有';T_Delphi - Fatal编程技术网

Delphi TMemo是如何吃掉一把逃生钥匙的,而TEdit没有';T

Delphi TMemo是如何吃掉一把逃生钥匙的,而TEdit没有';T,delphi,Delphi,我正试图阻止TMemo(以及TRichEdit)控件吃Escape键 如果用户的注意力集中在TEdit,则按Escape将触发表单执行用户按Escape时表单执行的操作。如果用户的注意力集中在TMemo中,则按escape键会被TMemo吃掉 我当然可以做黑客: procedure TForm1.Memo1KeyPress(Sender: TObject; var Key: Char); begin if Key = #27 then begin //figure

我正试图阻止
TMemo
(以及
TRichEdit
)控件吃
Escape

如果用户的注意力集中在
TEdit
,则按
Escape
将触发表单执行用户按Escape时表单执行的操作。如果用户的注意力集中在
TMemo
中,则按escape键会被
TMemo
吃掉

我当然可以做黑客:

procedure TForm1.Memo1KeyPress(Sender: TObject; var Key: Char);
begin
    if Key = #27 then
    begin
       //figure out how to send a key to the form
    end;
end;
Form1.KeyPreview := True;

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
   if Key = #27 then
   begin
      //Figure out how to invoke what the form was going to do when the user presses escape
   end;
end;
但这并不理想(我必须处理转义键,而不是让窗体处理它)

我当然可以做黑客:

procedure TForm1.Memo1KeyPress(Sender: TObject; var Key: Char);
begin
    if Key = #27 then
    begin
       //figure out how to send a key to the form
    end;
end;
Form1.KeyPreview := True;

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
   if Key = #27 then
   begin
      //Figure out how to invoke what the form was going to do when the user presses escape
   end;
end;
但这并不理想(我必须处理转义键,而不是让窗体处理它)

因此,我们将回答问题,而不是问题 相反,我们将借此机会学习一些东西。当
TEdit
没有以下功能时,
TMemo
如何接收到与之相关的按键事件:

procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
    if Key = #27 then
    begin
        //never happens
    end;
end;
TEdit
TMemo
是相同的窗口

为什么escape会绕过表单的KeyPreview 如果我打开表单的
键预览
,用户在聚焦于
TEdit
框时按下
Escape
,并且设置了按钮的
Cancel
属性,则表单关闭并:

  • 未触发
    Edit1.KeyPress
    事件
  • 未触发
    Form1.KeyPress
    事件
如果创建了一个动作,其
快捷方式
Esc
,则无论用户关注哪个控件,都不会引发
按键
事件


tl;dr:TMemo.WantEscape属性在哪里?

您观察到的行为由
WM_GETDLGCODE
消息的处理控制。对于类似以下内容的备忘录:

procedure TCustomMemo.WMGetDlgCode(var Message: TWMGetDlgCode);
begin
  inherited;
  if FWantTabs then Message.Result := Message.Result or DLGC_WANTTAB
  else Message.Result := Message.Result and not DLGC_WANTTAB;
  if not FWantReturns then
    Message.Result := Message.Result and not DLGC_WANTALLKEYS;
end;
Mask := 0;
case CharCode of
  VK_TAB:
    Mask := DLGC_WANTTAB;
  VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN:
    Mask := DLGC_WANTARROWS;
  VK_RETURN, VK_EXECUTE, VK_ESCAPE, VK_CANCEL:
    Mask := DLGC_WANTALLKEYS;
end;
if (Mask <> 0) and
  (Perform(CM_WANTSPECIALKEY, CharCode, 0) = 0) and
  (Perform(WM_GETDLGCODE, 0, 0) and Mask = 0) and
  (GetParentForm(Self).Perform(CM_DIALOGKEY,
  CharCode, KeyData) <> 0) then Exit;
对于编辑控件,VCL不会对
WM_GETDLGCODE
执行特殊处理,而底层Windows编辑控件会对其进行处理

在标准Win32应用程序中,Windows对话框管理器发送
WM\u GETDLGCODE
消息。但是Delphi不是建立在对话框管理器之上的,因此VCL负责发送
WM_GETDLGCODE
。它在
CN\u键下处理程序中执行此操作。代码如下所示:

procedure TCustomMemo.WMGetDlgCode(var Message: TWMGetDlgCode);
begin
  inherited;
  if FWantTabs then Message.Result := Message.Result or DLGC_WANTTAB
  else Message.Result := Message.Result and not DLGC_WANTTAB;
  if not FWantReturns then
    Message.Result := Message.Result and not DLGC_WANTALLKEYS;
end;
Mask := 0;
case CharCode of
  VK_TAB:
    Mask := DLGC_WANTTAB;
  VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN:
    Mask := DLGC_WANTARROWS;
  VK_RETURN, VK_EXECUTE, VK_ESCAPE, VK_CANCEL:
    Mask := DLGC_WANTALLKEYS;
end;
if (Mask <> 0) and
  (Perform(CM_WANTSPECIALKEY, CharCode, 0) = 0) and
  (Perform(WM_GETDLGCODE, 0, 0) and Mask = 0) and
  (GetParentForm(Self).Perform(CM_DIALOGKEY,
  CharCode, KeyData) <> 0) then Exit;
另一种方法是处理
CM\u WANTSPECIALKEY
WM\u GETDLGCODE
。下面是一个粗糙的插入器,演示了该技术:

type
  TMemo = class(StdCtrls.TMemo)
  protected
    procedure CMWantSpecialKey(var Msg: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
    procedure WMGetDlgCode(var Msg: TWMGetDlgCode); message WM_GETDLGCODE;
  end;

procedure TMemo.CMWantSpecialKey(var Msg: TCMWantSpecialKey);
begin
  case Msg.CharCode of
  VK_ESCAPE:
    Msg.Result := 0;
  VK_RETURN, VK_EXECUTE, VK_CANCEL:
    Msg.Result := 1;
  else
    inherited;
  end;
end;

procedure TMemo.WMGetDlgCode(var Msg: TWMGetDlgCode);
begin
  inherited;
  Msg.Result := Msg.Result and not DLGC_WANTALLKEYS;
end;

您可以随时捕获WM_KeyDown(或WM_SysKeyDown,不记得)消息。这是触发事件的第一个位置,您可以设置
Handled:=True
来使用它。老实说,我发现VCL
OnKeyPress
事件有一种非常奇怪的行为(特别是如果你使用表单的
KeyPreview
),所以它确实是
EDIT
控件内部的一种深层次的东西,可以自己处理它们吗?@Ian我认为现在更好了。