在Visual Studio中,KeyDown事件、KeyPress事件和KeyUp事件之间的区别是什么?

77
有人能告诉我 KeyDown 事件、KeyPress 事件和 KeyUp 事件之间的区别吗?我查看了MSDN网站,但没有太多解释。
请问这些事件发生的时机在逻辑上简单易懂的情况下能否说明一下?我感觉所有这些事件都是在按下键盘按键时发生的。那么它们之间的确切区别是什么呢?
5个回答

92

MSDN文档清晰地说明了三个事件的顺序:

按键事件按照以下顺序发生:

  1. KeyDown
  2. KeyPress
  3. KeyUp

KeyDown在用户按下键盘上的键时立即触发,当用户仍然按住该键时。

KeyPress只对字符键触发(与KeyDown和KeyUp不同,它们也对非字符键触发),而且在按下键时触发。这是比KeyDown或KeyUp更高级的事件,因此EventArgs中提供了不同的数据。

KeyUp在用户释放键盘上的键后触发。

通常情况下,应该处理KeyUp事件。在用户释放键后再启动UI操作。由于KeyUp是比KeyPress低级的事件,因此您将始终可以获得有关按下的键的丰富信息,甚至可以用于处理非字符键。


但要注意,所有这些事件都只能被具有焦点的控件触发。这意味着如果您的窗体上有一个按钮控件当前具有焦点,那么您的窗体的任何按键事件都不会触发。这经常让.NET新手感到困惑。处理这个最好的方法是重写窗体的ProcessCmdKey方法

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    if (keyData == (Keys.Control | Keys.A))
    {
        MessageBox.Show("You pressed Ctrl+A!");
    }
    return base.ProcessCmdKey(ref msg, keyData);
}

或许可以创建一个信息聚合网站,采用问答格式,以便轻松获取相关信息?并不是总能从原始文档中找到理想的解决方案... - weberc2
@Clay 他们没有这样的图表,因为事件/消息的顺序(一般来说)随时可能会改变。这是底层控件的实现细节,因此您不能依赖于所有可用消息的特定顺序。但是,由于它们的设计和含义,某些特定的消息总是按照特定的顺序发送的。例如,我在这里提到的那些。WinForms文档对于与键相关的事件有一个相当好的解释,我认为。 - Cody Gray
3
如果你处理KeyUp,当用户按住键时你将不会得到重复的响应。并且,仅在释放键时才发生某些事情是不正确的说法。这对于点击按钮是正确的,但对于按键则不是。 - Dave Cousineau
1
如果将窗体的 KeyPreview 属性设置为 true,您可以获取一个表单来响应通常由表单上的控件处理的关键事件。 - bmadtiger
1
@Max:你应该调用基类的实现:return base.ProcessCmdKey(ref msg, keyData); - Cody Gray
显示剩余2条评论

72
  • 按键按下事件(KeyDown):当用户按下一个按键时发生,指的是当键盘检测到手指按在按键上时发生。

  • 按键按下并释放事件(KeyPress):当按键被按下并释放时发生。

  • 按键释放事件(KeyUp):当用户松开按键时发生。

您说得对,所有这些事件都发生在按键按下然后释放的顺序中。


2
尽管Reggie没有问这个问题,但我在下面添加了一个答案,阐述何时使用KeyDown和KeyUp。 - Jim C
9
KeyPress的描述有误。即使键没有释放,只要按下键就会触发KeyPress事件。请参考Cody Gray的回答 - Juan
KeyPress 只会触发一次。如果按键被按住,KeyDown 会持续触发。 - ourmandave

8
这里有一个情况,当你不想使用KeyUp时:
你有一个列表框,并且在行上按Enter键会调用编辑对话框。问题是:如果用户在编辑器的“确定”按钮上按Enter键,则KeyUp(e.KeyCode = Enter)事件将泄漏回列表框,导致编辑器重新打开。如果用户在编辑器的“确定”按钮上按空格键,则不会发生这种情况;在这种情况下,KeyUp(e.KeyCode=Space)事件会在编辑器关闭之前被处理。
这是我使用的选择启发式方法:
If I'm handling the Enter key and I need to guard against a case like the one above
  then I use KeyDown    
Else if I'm handling key combinations (e.g. CTRL+C)
   then I favor* KeyDown (KeyUp can make these awkward)   
Else if I am allowing press & hold autorepeat
  then I use KeyDown    
Else 
  I use KeyUp

*如果某个行为在常用产品中(如Microsoft Office)可以完成,例如CTRL+A(选定全部),那么我会模仿Microsoft的行为方式,因为用户已经习惯了这种方式。


非常有帮助的想法,吉姆。但是,这不会导致不一致的体验吗?可以争论这种情况不应该发生,因为对话框在按键抬起事件之前不应该起作用。到目前为止,我一直使用KeyUp(对于Enter键)以保持一致性,但我遇到了你提到的状态问题。 - O'Rooney
在WPF中,可以通过在预览事件中处理Enter键来防止其“泄漏”,对吗? - Sabuncu
谢谢 - 我在 KeyUp 中无法捕获 "Alt-F4" ... 必须使用 KeyDown。 - Jess

5

除了其他答案之外:

在尝试确定将动作连接到这些事件中的哪一个时,请注意,当按键按下时将多次触发KeyDown事件。有时您需要此行为,有时不需要。基于此,我建议以下用法(根据我的经验):

(事件触发顺序)

KeyDown

发生时间: 按钮按下并持续按下时
用途: 即刻在按钮按下时执行操作甚至多次执行操作
示例: 使用箭头键移动光标

.

KeyPress

发生时间: 按下字符键(更高级别的事件)
用途: 与输入文本相关的任何内容
示例: 处理文本框输入

.

KeyUp

发生时间: 松开键盘按键
用途: 执行关键动作,每个击键只应发生一次
示例: 将数据写入文件


2

KeyDownKeyPressKeyUp的顺序是我发现的。

通常情况下,当用户按住控制键进行多模输入时(例如shift-click操作),你需要挂钩KeyDownKeyPress用于简单的按键输入逻辑,只需获取按键;KeyUp被挂钩以在其他东西处理KeyPress后执行逻辑,例如修改文本编辑框的内容。老实说,我并不经常使用KeyUp,但有时它是获取消息的唯一方法,因为其他东西已经处理了KeyPress,你需要检查/修复发生的事情。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接