【问题标题】:Delphi XE2: How to prevent the Alt key stealing focus?Delphi XE2:如何防止 Alt 键窃取焦点?
【发布时间】:2013-05-25 13:28:03
【问题描述】:

当光标在例如在编辑字段中,按下并释放 Alt 键(不按任何其他键)会导致编辑字段失去焦点。任何其他集中控制也会发生这种情况。如何在 Delphi 程序中针对任何集中控制来防止这种情况发生?

【问题讨论】:

  • 停止尝试解决没有问题的事情。 所有 Windows 程序都以这种方式运行。按 Alt 时,菜单会被激活。如果您的窗口没有主菜单,则会激活多个窗口(通过单击左上角的图标获得的窗口)。您可以通过使用箭头键浏览窗口的菜单来看到这一点。解决这个问题的方法是更好的用户教育,而不是试图改变你的程序的行为。当焦点被盗时,只需再次按 Alt 或 Esc 即可取消菜单模式。
  • 拦截所有窗口消息并过滤掉那些打开菜单的消息。但是你有很多机会完全打破这个程序。如果你的用户很笨,最好给他们做一个大baner,当他们打开菜单时会显示,这样他们就会知道他们必须回到输入框。
  • @Rob Kennedy 我理解您关于 Windows 一致性的发言,总的来说我同意您的看法。但是,在非常特殊的情况下,防止 Alt 键窃取焦点可能很有用。同时我找到了一个解决方案:在控件的 OnKeyDown 事件处理程序中,您希望避免使用 Alt 键失去焦点:if Shift = [ssAlt] then Key := 0;
  • 这会杀死所有的 Alt+something 热键,也许某些基于 AltGr 的变音符号将不再可用
  • 正如我所说:在“非常特殊的情况下”(不需要 Alt+某些东西)。

标签: delphi delphi-xe2 alt-key


【解决方案1】:

在减少意外后果的情况下做到这一点的更好方法是非常精确 - 我建议:

在您的表单中,覆盖 WndProc :

TForm1 = class(TForm)
  Edit1: TEdit;
private
   FSuppress : boolean;
protected
   procedure WndProc(var Message : TMessage); override;
end;

并像这样实现:

procedure TForm1.WndProc(var Message : TMessage);
begin
  if (Message.Msg = WM_SYSCOMMAND) and
     (Message.WParam = SC_KEYMENU) and
     FSuppress then Exit;

  inherited WndProc(Message);
end;

这是系统命令的 windows 消息和特定的 WParam,表明它用于检索由击键触发的菜单。在您希望保持焦点的任何控件上设置FSuppress

procedure TForm1.Edit1Enter(Sender: TObject);
begin
  FSuppress := true;
end;

procedure TForm1.Edit1Exit(Sender: TObject);
begin
  FSuppress := false;
end;

这不会禁用 ALT 键,但会在 Edit1 获得焦点时禁用菜单的激活。至关重要的是,诸如 ALT + F4 退出程序或 ALT+TAB 切换窗口之类的快捷方式仍然有效。

不过,我同意大多数 cmets,因为这可能不是您的用户群 LCD 的最佳解决方案。您实际上是在削弱程序,让有能力的用户迎合无能的用户的失败。也许将其作为 Windows 粘滞键或各种残疾人的辅助功能选项之类的选项。

【讨论】:

  • 仅供参考,您建议定义的两个常量都已在 Windows.pas 中定义,并且至少从 Delphi 2 开始就已定义。由于这是 VCL 表单的单元,Windows已经在uses子句中,声明是多余的。
  • @KenWhite 我是这么认为的......错误洞察声称它们是未知的,所以我只是将它们添加进去。有时我认为错误洞察需要强调自身。
  • 谢谢,这是一个完美的解决方案。正如我已经说过的:这是针对一种非常特殊的情况。当然,我已经更改了变量名。
【解决方案2】:
procedure SendKey_ALT;
begin
    keybd_event(VK_MENU, MapVirtualKey(VK_MENU, 0), 0, 0);
    keybd_event(VK_MENU, MapVirtualKey(VK_MENU, 0), KEYEVENTF_KEYUP, 0);
end;

在您的 FormCreate() 方法中调用上述过程。 这样就可以解决问题了。

【讨论】:

    猜你喜欢
    • 2011-11-04
    • 1970-01-01
    • 1970-01-01
    • 2011-02-18
    • 2016-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-04
    相关资源
    最近更新 更多