Delphi VCL 窗体箭头键管理解决方案触发两次

Delphi VCL form Arrow Key management solution fires twice

我有一个 VCL 窗体,其中包含许多 tframes(称为 tcellFrame),其中包含排列在网格中的组件。我正在使用鼠标点击和箭头键让用户在它们之间导航。鼠标点击工作正常,但在我发现这个问题线程之前,我在使用箭头键时遇到了问题:Delphi XE and Trapping Arrow Key with OnKeyDown。 Sertac Akyuz 的答案中的解决方案确实处理了使用

将箭头键消息发送到表单的问题
procedure TForm1.DialogKey(var Msg: TWMKey);
begin
  case Msg.CharCode of
    VK_DOWN, VK_UP, VK_RIGHT, VK_LEFT:
      if Assigned(onKeyDown) then
        onKeyDown(Self, Msg.CharCode, KeyDataToShiftState(Msg.KeyData));
    else
      inherited
  end;
end;

但每次击键都会对表格进行两次操作。它没有向左移动一个单元框,而是移动了两个。使用调试器跟踪线程表明 onkeydown 事件被调用了两次。

我的 onKeyDown 活动结构如下:

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
var
  i : integer;
  g, r, c, str : string;
  tmpFrame : tcellFrame;  //frame component containing tlabels
begin
  ...

  case key of
    VK_UP:
      begin
        //calc new cell location values for g,r,c
        str := ('Cell'+g+r+c);
        picklist.Clear;  // picklist is a form-wide tstringlist variable containing currently selected cellframes.
        picklist.add (str);
        TmpFrame := FindComponent(picklist [0]) as TCellFrame;
        tmpframe.Color := pickClr;
      end;
    //VK_DOWN, VK_LEFT, VK_RIGHT: defined similarly to VK_UP

  end;
end;

Formkeydown 中有更多代码,但都是内部计算来确定正确的 tcellframe 名称以放置在选择列表中。

我的问题是:

在您的 CM_DIALOGKEY 消息处理程序中,如果您处理密钥,return 一个非零值,则不会进一步发送它。

procedure TForm1.DialogKey(var Msg: TWMKey);
begin
  case Msg.CharCode of
    VK_DOWN, VK_UP, VK_RIGHT, VK_LEFT:
      begin
        if Assigned(onKeyDown) then
          onKeyDown(Self, Msg.CharCode, KeyDataToShiftState(Msg.KeyData));
        Msg.Result := 1; // <-- add this
      end;
    else
      inherited;
  end;
end;

但是,如果你的Form上有KeyPreview=True,而且方向键已经正常派发了,那么根本就不需要处理CM_DIALOGKEY,直接让Form的[=14] =] 事件得到正常调度。您不应该从 CM_DIALOGKEY 处理程序触发表单的 OnKey... 事件。

有关详细信息,请参阅 A Key's Odyssey