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。
我有一个 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。