1

在编码一个小游戏的时候,遇到了一个问题;我的表单KeyDownKeyUp事件根本不会触发。

这是表单的代码:

public class GameForm : Form
{
    private ControllableBlock player;

    public GameForm()
    {
        KeyDown += Game_KeyDown;
        KeyUp += Game_KeyUp;

        player = new ControllableBlock();
        Controls.Add(player);
    }

    private void Game_KeyDown(object sender, KeyEventArgs e)
    {
        player.ReactToKey(e.KeyCode);
    }

    private void Game_KeyUp(object sender, KeyEventArgs e)
    {
        player.ReactToKey(e.KeyCode);
    }
}

还有很多事情要做,但我只粘贴了相关代码。

我已经尝试过设置this.KeyPreview = true;和调用this.Focus();,都不起作用。问题不在于ReactToKey()方法,我已经在那里设置了一个断点,并且该事件永远不会被触发。


编辑:经过一些测试,我得出的结论是问题出在我的ControllableBlock. 然而,我不知道为什么,但我正在努力。如果我注释掉与 相关的所有内容,player事件就会开始触发。


编辑 2:似乎问题是我ControllableBlockControl. 如果我从 继承它Panel,它工作正常。 为什么是这样?如果我从控件继承,我不能触发事件吗? 这个ControllableBlock类现在是空的,所以它甚至不做任何事情,除了继承自Control.


编辑3:既然我已经开始了赏金,我想澄清一下,我不是在寻找如何让事件触发的解决方案,我正在寻找他们为什么不触发的原因我继承自Control.

4

4 回答 4

4

如果您的事件应该是应用程序范围内的,请尝试将属性设置KeyPreviewtrue- 它允许您触发相应的事件,而不管焦点控制如何。

this.KeyPreview = true;

否则,您应该将这些事件直接附加到将处理它们的控件。

编辑:

InitializeComponent();从我的表格中删除并得到与你相同的行为。

在实施问题中提供的解决方案后,所有事件都开始完美地进行。
在此处复制代码段:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
        if (keyData == Keys.Left) {
            // Do your staff for Left Key here

            return true;
        }
        // you need to add if condition to every direction you want to handle
        return base.ProcessCmdKey(ref msg, keyData);
    }
于 2013-02-26T14:17:06.997 回答
3

我能够重现一个类似的问题(希望是相关的..)

解释:

  • CanSelect==true键盘输入可选择返回的控件
  • 一个空白的后代Control()是可选的,其中一个Panel()不是
  • 添加到表单的第一个可选控件将被选中
  • 默认情况下,选定的控件将从其父级窃取键盘事件
  • 用于在窗口内导航的某些键需要额外的步骤才能处理

在这里查看Windows 键盘输入如何工作的一个很好的概述。

重现它的代码:

public class GameForm : Form
{
    public GameForm()
    {
        this.KeyDown += Game_KeyDown;
        var tests = new List<Control[]>() { 
            new[] { new Panel() },
            new[] { new Panel(), new Panel() },
            new[] { new Control() },
            new[] { new Control(), new Panel() },
            new[] { new Panel(), new Control() }
        };
        // When test index 2 to 4 used, keyboard input does not reach form level
        Controls.AddRange(tests[0]);            
        // When uncommented, ensures all keyboard input reaches form level
        /*this.KeyPreview = true;              
        // Additional plumbing required along with KeyPreview to allow arrow and other reserved keys
        foreach (Control control in this.Controls)
        {
            control.PreviewKeyDown += control_PreviewKeyDown;
        }*/
    }
    void control_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
    {
        e.IsInputKey = true;
    }
    private void Game_KeyDown(object sender, KeyEventArgs e)
    {
        // breakpoint here
        Debug.WriteLine(e.KeyCode);
    }
}
于 2013-06-13T17:02:35.523 回答
0

尝试将处理程序设置移动到 Form_Load 事件而不是构造函数。Initialize()构造函数中不应该调用吗?我不会特别推荐删除它

如果ControllableBlock从 Panel 继承,它将具有比基本 Control 对象更多的事件连接和更好的 UI 交互设置。

于 2013-02-26T14:16:52.157 回答
0

您需要使您的控件可选择,然后它才能接收焦点。

尝试将以下内容添加到您的构造函数中:

this.SetStyle(ControlStyles.Selectable, true);

并确保在表单显示后给予焦点。或者,覆盖 OnMouseDown() 并在其中调用 this.Focus() 。

于 2013-02-26T14:19:32.393 回答