如何在表单上无论焦点控件如何,捕获Keys.F1按键?

30

我使用了KeyDown事件和一些简单的代码,例如if (e.KeyCode == Keys.F1)来捕获在表单上按下F1键,但如果在表单上有一些文本框或者有一些使用Dock Fill 的电子表格,那么以上代码将变得无用并且不起作用。但是我想要在用户按下此表单上的F1键时执行某些操作。那么我们如何能够捕获整个表单上的特定按键事件,例如F1? 我不想走捕获表单上所有其他控件的KeyDown事件并将它们传递给表单进行处理的路线。是否有更加干净的方法来做到这一点?

4个回答

60

是的,确实有方法。无论当前具有输入焦点的控件是什么,处理关键事件的表单正确的方式是覆盖表单类的ProcessCmdKey方法

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    if (keyData == Keys.F1)
    {
        MessageBox.Show("You pressed the F1 key");
        return true;    // indicate that you handled this keystroke
    }

    // Call the base class
    return base.ProcessCmdKey(ref msg, keyData);
}

你需要返回true来表明你已处理了按键并且不希望将其传递给其他控件。如果你希望将其传递给其他控件的事件处理程序,只需返回false

最好忽略KeyPreview属性。这是VB 6时代的陈旧之物,不是.NET世界中首选的方式。更多阅读:设置Form.KeyPreview = true有什么缺点?


5
这不是首选的方式吗?KeyPreview利用了.NET的事件中心架构,而您只是覆盖了WndProc,这是Win3.1(没错,就是1992年的技术)首选的方法。 - Blindy
1
@Blindy:在Windows API的世界中,惯用的做法自从Windows早期以来就没有太大变化。虽然重写WndProc也可以实现,但这并不是完全相同的事情。框架会在适当的时候专门调用此方法来处理这些事件。此外,以这种方式处理事件允许您决定是否要将事件传递给其他控件。 - Cody Gray
1
实际上,当 uMsg=WM_KEYDOWN 时覆盖 WndProc 和检查 Win32 API 中的虚拟键代码一样。而且,就像检查 Win32 API 中的虚拟键代码一样,您不知道用户输入的是实际键还是其移位版本(以及其他内容)。各有所好,但我会更加小心地选择调用哪个API。 - Blindy
1
@Blindy:是功能上的还是惯用语?我不在争论功能方面——我已经说过这样做同样有效。但我强烈不同意KeyPreview是更好的选择。 - Cody Gray
如果WebBrowserControl具有焦点,这似乎无法正常工作。 - Thomas Weller

5

将表单的KeyPreview设置为true。这将确保表单首先获取按键消息,如果您处理它,可以设置e.Handled = true,以便它不会传递到控件。


4

开启KeyPreview后,表单中的每个按键都会先通过它的键事件处理程序进行路由。



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