触发键盘按下事件的火焰表单密钥

7
我有一个C#的winform窗体,在上面有一个按钮。
现在,当我运行我的应用程序时,这个按钮会自动获得焦点。
问题是,我的窗体的KeyPress事件无法响应,因为按钮已经获取了焦点。
我尝试在FormLoad()���件中使用this.Focus()方法,但是KeyPress事件仍然无法响应。
5个回答

11
你需要覆盖你的窗体中的 ProcessCmdKey 方法。这是唯一能让你在子控件具有键盘焦点时获得键事件通知的方法。
示例代码:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    // look for the expected key
    if (keyData == Keys.A)
    {
        // take some action
        MessageBox.Show("The A key was pressed");

        // eat the message to prevent it from being passed on
        return true;

        // (alternatively, return FALSE to allow the key event to be passed on)
    }

    // call the base class to handle other key events
    return base.ProcessCmdKey(ref msg, keyData);
}
关于为什么this.Focus()无效,是因为一个窗体本身不能拥有焦点。特定的控件必须拥有焦点,因此当您将焦点设置到窗体时,实际上是将焦点设置到可以接受焦点且具有最低TabIndex值的第一个控件上。在这种情况下,就是您的按钮。

3
请注意,ProcessCmdKey()不能替代KeyPress。虚拟键和它们所对应的字符之间有很大的区别。没有好的方法来获取与KeyPress等效的结果。 - Hans Passant

5

尝试将表单的KeyPreview属性设置为True。


好的,但是当我的按钮也有keyPress事件时,两个keyPress事件都会被触发。 - Javed Akram
这并不是一个好的解决方案。它不能适用于所有可能的键,它不能防止控件窃取键事件,并且更多地是处理事情的老式VB 6方式。覆盖ProcessCmdKey是惯常的方法。 - Cody Gray
@CodyGray:然而,当目标是接收 KeyPress 事件时,这是一个合适的替代方案。显然,在使用它时需要小心谨慎,但通常比尝试将特定键事件映射到字符更容易/简单。 - Peter Duniho

1

在主窗体上设置 keyPreview = true


0

我曾经遇到过同样的问题,虽然这个问题早已得到解答,但我的解决方案来自于另一个堆栈溢出的问题,其中我的唯一按钮被抓住并保持焦点。我接受了用户的建议,并创建了一个无法获得焦点的按钮。

也许有人会觉得这很有用:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace I2c_Programmer {
    class NoSelectButton : Button{

            public NoSelectButton() {

            SetStyle(ControlStyles.Selectable, false);

        }
    }
}

进入您的设计师,在创建按钮的位置,用您的新类 "new NoSelectButton();" 替换新的 System... 按钮。


0

我会使用以下其中之一

  1. 将按钮的TabIndex属性设置为0。

  2. 将按钮的IsDefault属性设置为true-因此,在按下ENTER键时,它将被触发。


嗯,他说当窗体加载时按钮已经获得了焦点,所以我只能假设它在用户按下Enter(或Space)键时已经响应了。问题没有指定他想要捕捉的特定键;我怀疑它可能不是Enter键。 - Cody Gray

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