简体   繁体   English

KeyDown事件无法触发?

[英]KeyDown event not firing?

When coding a small game, I encountered a problem; 在编写小型游戏时,我遇到了问题。 my form's KeyDown and KeyUp events don't fire at all. 我的窗体的KeyDownKeyUp事件根本不会触发。

This is the form's code: 这是表单的代码:

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);
    }
}

There's a lot more going on, but I only pasted the relevant code. 还有很多事情要做,但是我只粘贴了相关代码。

I've already tried setting this.KeyPreview = true; 我已经尝试过设置this.KeyPreview = true; and calling this.Focus(); 并调用this.Focus(); , neither works. ,均无效。 The problem is not in ReactToKey() method, I've already set a breakpoint there and the event is never fired. 问题不在ReactToKey()方法中,我已经在那里设置了一个断点,并且该事件从未触发过。


Edit: After some tests I've come to a conclusion that the problem is within my ControllableBlock . 编辑:经过一些测试,我得出的结论是问题在我的ControllableBlock Yet, I have no idea why, but I'm working on it. 但是,我不知道为什么,但是我正在努力。 If I comment out everything that's related to the player , the events start firing. 如果我注释掉与player相关的所有内容,则事件开始触发。


Edit 2: Seems like the problem is me inheriting my ControllableBlock from Control . 编辑2:似乎问题出在我从Control继承了ControllableBlock If I inherit it from Panel , it works fine. 如果我从Panel继承它,它将正常工作。 Why is this? 为什么是这样? Can't I fire an event if I inherit from control? 如果我从控件继承,就不能触发事件? The ControllableBlock class is empty for now, so it doesn't even do anything other than inherits from Control . ControllableBlock类目前为空,因此除了继承Control之外,它甚至不做任何其他事情。


Edit 3: Now that I've started a bounty, I'd like to clarify that I'm not looking for a solution on how to make the events fire, I'm looking for a reason on why they don't fire if I inherit from Control . 编辑3:既然我已经开始了赏金计划,我想澄清一下,我不是在寻找使事件触发的解决方案,而是在寻找为什么事件不会触发的原因我继承自Control

If your events should be application-wide try to set property KeyPreview to true - it will allow you to fire respective events regardless of focused control. 如果您的事件应在整个应用程序范围内,请尝试将属性KeyPreview设置为true ,这将使您可以触发各个事件,而无需进行集中控制。

this.KeyPreview = true;

Otherwise you should attach these events directly to control that will process them. 否则,您应该将这些事件直接附加到将处理这些事件的控件上。

Edit: 编辑:

I removed InitializeComponent(); 我删除了InitializeComponent(); from my form and got behaviour identical to yours. 从我的表单中获得的行为与您的行为相同。

After implementing solution provided in this question all events started to qork perfectly. 实施问题提供的解决方案后,所有事件开始完美地响起来。
Copy code snippet here: 在此处复制代码段:

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);
    }

I was able to reproduce a similar issue (which is hopefully related..) 我能够重现类似的问题(希望是相关的。)

Explanation: 说明:

  • Controls which return CanSelect==true are selectable for keyboard input 返回CanSelect==true控件对于键盘输入是可选的
  • A blank descendent of Control() is selectable, one of Panel() is not 可以选择Control()空白后代,而Panel()则不能
  • The first selectable control added to a form will get selected 添加到表单的第一个可选控件将被选中
  • A selected control will steal keyboard events from its parents by default 所选控件默认会从其父控件窃取键盘事件
  • Certain keys used for navigation within a window require extra steps to be handleable 窗口中用于导航的某些键需要额外的步骤才能处理

Check here for a good overview of how windows keyboard input works. 在此处查看有关Windows键盘输入如何工作的良好概述。

Code to reproduce it: 复制代码:

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);
    }
}

try moving the handler setup to the Form_Load event rather than the constructor. 尝试将处理程序设置移至Form_Load事件而不是构造函数。 Should there not be a call to Initialize() in the constructor? 构造函数中应该没有对Initialize()的调用吗? I wouldn't particularly recommend removing it 我不建议您删除它

If ControllableBlock inherits from Panel, it will have more event hookups and better UI interaction setup than a base Control object. 如果ControllableBlock从Panel继承,则与基本Control对象相比,它将具有更多的事件连接和更好的UI交互设置。

You need to make your control selectable before it can receive the focus. 您需要使控件处于可选状态,然后才能获得焦点。

Try adding the following to your constructor: 尝试将以下内容添加到构造函数中:

this.SetStyle(ControlStyles.Selectable, true);

And ensure that you give your form focus after it has been displayed. 并确保在显示表单焦点后为其赋予焦点。 Or, override OnMouseDown() and call this.Focus() in it. 或者,重写OnMouseDown()并在其中调用this.Focus()。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM