【问题标题】:delphi custom component - catching (ctrl or alt key) keydown and keyup keyeventsdelphi 自定义组件 - 捕获(ctrl 或 alt 键)keydown 和 keyup 键事件
【发布时间】:2016-08-06 18:24:45
【问题描述】:

我有一个自定义组件(tpanel 的后代),我想做的是捕捉 ctrl 或 alt 键何时按下和按下

知道怎么做吗?

【问题讨论】:

  • 您发布的所有代码都是无关紧要的。请edit您的帖子仅包含代码的相关部分。不要指望我们费尽千辛万苦才能看到与您的帖子实际相关的部分。
  • 我做了更改 :) 希望它现在看起来更好?

标签: delphi components key-events


【解决方案1】:

方法是覆盖 KeyDown()KeyUp() 受保护的方法。这些方法的Key 参数是对应于向下/向上键的Virtual Key code

对于 Ctrl 键,感兴趣的键代码是 VK_CONTROL

Alt 键的键码是稍微不那么明显的VK_MENU

这些键码不区分键盘上的左键/右键。如果这很重要,您可以使用 VK_LCONTROLVK_RCONTROLVK_LMENUVK_RMENU

因此,例如,如果您要在布尔成员变量中维护 Ctrl 键状态,您可以在 Ctrl 键关闭时设置此 TRUE,类似于以下内容:

procedure TMyButton.KeyDown(var Key: Word; Shift: TShiftState);
begin
  inherited;
  fCtrlKeyDown := (Key = VK_CONTROL);
end;

但是,这些事件将在您的控件具有输入焦点时在您的控件具有输入焦点时发生

因此,如果用户按下 Ctrl 键,而其他控件具有焦点,您的控件将不会意识到这一点。如果您需要随时了解键的状态,请致电GetAsyncKeyState()

要在某个输入事件发生时获取某个键的状态(即窗口消息,例如鼠标按钮单击),然后在响应该事件的代码中调用GetKeyState()

要了解两者之间的区别,请考虑您有一些 Click 处理程序响应鼠标单击,该处理程序触发了一些可能消耗用户可能按下(或释放)a键,然后是一些取决于键状态的进一步处理:

procedure TMyButton.Click;
begin
  // .. some non-trivial processing - if the user presses or releases 
  //  the Ctrl key while this processing occurs, then this could affect
  //  how the following code behaves, depending on which 'KeyState'
  //  function is used to determine that key state ....

  // ...

  GetKeyState(VK_CONTROL);  // Will return the state of the Ctrl key at
                            //  the time of the mouse event that resulted 
                            //  in this Click code being executed, regardless
                            //  of the state of that key NOW.

  GetAsyncKeyState(VK_CONTROL);  // Will return the state of the Ctrl key NOW
                                 //  regardless of the state of the key at    
                                 //  the time of the 'Click' mouse event.
end;

注意GetAsyncKeyState() 的返回值不是一个简单的布尔值。它包含有关自上次调用该函数以来是否按下该键以及该键的当前状态的信息。

类似地,GetKeyState() 包含有关键的“切换”状态的信息,也不是简单的布尔值。

有关解释其返回值的详细信息,请参阅这些 API 的文档。

响应其他控件中的输入

如果您的控件需要能够立即响应按下的键而其他控件具有输入焦点,例如为了向键盘状态的用户提供一些视觉反馈,那么您将需要实现一些额外的机制,通过这些机制可以让控件知道这些事件。

一种方法是在表单上使用 KeyPreview 并在控件上提供一个方法,每当表单接收到键事件时都需要调用该方法(启用 KeyPreview 后,每个键都会发生事件,在实际输入控件接收到该事件之前。因此名称......事件允许表单“预览”“键”事件)。此方法可以使您的控件确定键盘状态并做出适当的响应和反应。

然而,这意味着您的控件依赖于外部代码(在表单上)才能运行,并且仍然仅适用于在同一表单上的某些控件具有输入焦点时发生的键盘事件。

为了让您的控件完全独立,它可以安装keyboard hook 来建立应用程序范围的“预览”机制。如果您的应用程序中可能有很多控件实例,您可能希望设计一种机制来跟踪这些实例并仅使用单个挂钩来更新它们,而不是每个控件都安装自己的挂钩。

我认为这里不适合详细介绍这种机制。如果您难以实现,那么这应该作为一个单独的问题来解决(可能已经在 StackOverflow 的其他地方得到了回答)。

【讨论】:

  • 我尝试覆盖 keydown() 和 keyup() 方法,但问题是我的组件来自 TPanel,并且当组件没有关注 keydown() 和 keydup() 方法时,没有关注组件没有响应并且组件没有捕获表单上的关键事件
  • 如果我理解正确的话,我已经更新了我认为的地址的答案。
  • 谢谢 deltics,问题是如何让我的组件知道 GetKeyState/GetAsyncKeyState 的变化?
  • 我需要知道是否按下并释放了 ctrl 或 alt 键,即使我的组件没有焦点
  • 再次感谢 deltics,我认为“键盘钩子”方法可以解决我的问题。有什么例子可以让我理解“键盘钩子”过程吗?
猜你喜欢
  • 2013-04-27
  • 2016-07-28
  • 2011-03-28
  • 1970-01-01
  • 1970-01-01
  • 2012-04-14
  • 1970-01-01
  • 2011-03-10
相关资源
最近更新 更多