【问题标题】:Up, Down, Left and Right arrow keys do not trigger KeyDown event上、下、左、右箭头键不触发 KeyDown 事件
【发布时间】:2009-10-29 22:36:47
【问题描述】:

我正在构建一个应用程序,其中所有的键输入都必须由窗口本身处理。

我将 tabstop 设置为 false,因为每个控制女巫都可以抓住除面板以外的焦点(但我不知道它是否有效)。

我将 KeyPreview 设置为 true,并且我正在处理此表单上的 KeyDown 事件。

我的问题是有时箭头键不再响应:

  • 当我只按下一个箭头键时,keydown 事件没有被触发。

  • 如果我按下带有控制修饰符的箭头键,就会触发 keydown 事件。

你知道为什么我的方向键突然停止触发事件吗?

【问题讨论】:

  • 您能否发布您在 KeyDown 事件处理程序中获得的代码。
  • 也许这会对你有所帮助? stackoverflow.com/questions/902767/…
  • @Maxim,我很确定如果窗口包含任何子控件,箭头键的键事件将被抑制。您链接到的问题涉及没有控件的表单。 Daniel Waltrip 的问题并不完全相同。
  • @Snarfblam 我不确定我是否理解 - 为什么这会是个问题?

标签: c# winforms keydown


【解决方案1】:

我遇到了完全相同的问题。我考虑了@Snarfblam 提供的答案;但是,如果您阅读 MSDN 上的文档,则 ProcessCMDKey 方法旨在覆盖应用程序中菜单项的键事件。

我最近偶然发现了这篇来自微软的文章,看起来很有希望:http://msdn.microsoft.com/en-us/library/system.windows.forms.control.previewkeydown.aspx。根据微软的说法,最好的办法是在检测到方向键后在PreviewKeyDown 事件中设置e.IsInputKey=true;。这样做会触发KeyDown 事件。

这对我来说效果很好,并且比覆盖 ProcessCMDKey 更少黑客攻击。

【讨论】:

  • 这应该是选择的答案,它更干净而且效果很好。
  • 是的,它有效!答案很清楚,但我想指定IsInputKeye 类中:e.IsInputKey=true
  • (如果你对所有键都这样做而不检测到箭头会发生什么?)
  • @T30 您将失去菜单的 Alt
【解决方案2】:
    protected override bool IsInputKey(Keys keyData)
    {
        switch (keyData)
        {
            case Keys.Right:
            case Keys.Left:
            case Keys.Up:
            case Keys.Down:
                return true;
            case Keys.Shift | Keys.Right:
            case Keys.Shift | Keys.Left:
            case Keys.Shift | Keys.Up:
            case Keys.Shift | Keys.Down:
                return true;
        }
        return base.IsInputKey(keyData);
    }
    protected override void OnKeyDown(KeyEventArgs e)
    {
        base.OnKeyDown(e);
        switch (e.KeyCode)
        {
            case Keys.Left:
            case Keys.Right:
            case Keys.Up:
            case Keys.Down:
                if (e.Shift)
                {

                }
                else
                {
                }
                break;                
        }
    }

【讨论】:

  • 请注意,所有控件的制表位都应该是假的。(我遇到了这样的问题:D)
  • 这实际上是一个 hack。检查 Rodolfo Neuber 的正确答案。
【解决方案3】:

我正在使用 PreviewKeyDown

    private void _calendar_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e){
        switch (e.KeyCode){
            case Keys.Down:
            case Keys.Right:
                //action
                break;
            case Keys.Up:
            case Keys.Left:
                //action
                break;
        }
    }

【讨论】:

  • 为我工作得很好,无需继承/覆盖
  • 这非常好用,谢谢。行为与我期望的关键事件完全一样。
  • 这应该是公认的答案!!!只需使用 PreviewKeyDown 事件。无需黑客攻击即可工作。再简洁不过了。
【解决方案4】:

请参阅Rodolfo Neuber's reply 以获得最佳答案


(我原来的答案):

从控件类派生,您可以覆盖 ProcessCmdKey 方法。 Microsoft 选择从 KeyDown 事件中省略这些键,因为它们会影响多个控件并移动焦点,但这使得应用很难以任何其他方式对这些键做出反应。

【讨论】:

  • 看来ProcessCmdKey是唯一能准确处理键盘的方法。谢谢!
  • 这个答案大错特错。如果我还没有从已经处理箭头键(以更改行为)的某些基本控件中覆盖 OnKeyDown,我将不会知道这一点并以艰难的方式实现它。请参阅下面的 alpha 答案。
  • 即使是 alpha 的回答也不适用于我的情况,但 Snarfblam 可以。谢谢!
【解决方案5】:

不幸的是,由于 KeyDown 事件的限制,使用箭头键很难做到这一点。但是,有几种方法可以解决这个问题:

  • 正如@Snarfblam 所说,您可以重写 ProcessCmdKey 方法,该方法保留解析箭头键按下的能力。
  • 正如the accepted answer from this question 所说,XNA 有一个名为Keyboard.GetState() 的内置方法,它允许您使用箭头键输入。但是,WinForms 没有此功能,但可以通过 P/Invokeusing a class that helps with it 来完成。

我建议尝试使用该类。这样做很简单:

var left = KeyboardInfo.GetKeyState(Keys.Left);
var right = KeyboardInfo.GetKeyState(Keys.Right);
var up = KeyboardInfo.GetKeyState(Keys.Up);
var down = KeyboardInfo.GetKeyState(Keys.Down);

if (left.IsPressed)
{
//do something...
}

//etc...

如果您将此与 KeyDown 事件结合使用,我认为您可以可靠地实现您的目标。

【讨论】:

    【解决方案6】:

    从 WinForms 调用 WPF 窗口时,我遇到了类似的问题。

    var wpfwindow = new ScreenBoardWPF.IzbiraProjekti();
        ElementHost.EnableModelessKeyboardInterop(wpfwindow);
        wpfwindow.Show();
    

    但是,将窗口显示为对话框,它起作用了

    var wpfwindow = new ScreenBoardWPF.IzbiraProjekti();
        ElementHost.EnableModelessKeyboardInterop(wpfwindow);
        wpfwindow.ShowDialog();
    

    希望这会有所帮助。

    【讨论】:

      【解决方案7】:

      为了在 Forms 控件中捕获击键,您必须派生一个基于所需控件类的新类,并重写 ProcessCmdKey()。

      protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
      {
          //handle your keys here
      }
      

      例子:

      protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
      {
          //capture up arrow key
          if (keyData == Keys.Up )
          {
              MessageBox.Show("You pressed Up arrow key");
              return true;
          }
      
          return base.ProcessCmdKey(ref msg, keyData);
      }
      

      完整来源...Arrow keys in C#

      薇恩

      【讨论】:

        【解决方案8】:

        我认为最好的方法是像 MSDN 上所说的那样处理它 http://msdn.microsoft.com/en-us/library/system.windows.forms.control.previewkeydown.aspx

        但是处理它,你真的需要它。我的方法(在下面的示例中)是捕获每个 KeyDown ;-)

            /// <summary>
            /// onPreviewKeyDown
            /// </summary>
            /// <param name="e"></param>
            protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e)
            {
                e.IsInputKey = true;
            }
        
            /// <summary>
            /// onKeyDown
            /// </summary>
            /// <param name="e"></param>
            protected override void OnKeyDown(KeyEventArgs e)
            {
                Input.SetFlag(e.KeyCode);
                e.Handled = true;
            }
        
            /// <summary>
            /// onKeyUp
            /// </summary>
            /// <param name="e"></param>
            protected override void OnKeyUp(KeyEventArgs e)
            {
                Input.RemoveFlag(e.KeyCode);
                e.Handled = true;
            }
        

        【讨论】:

          【解决方案9】:

          我遇到了同样的问题,并且已经在使用所选答案中的代码。这个链接是我的答案;也许也适用于其他人。

          How to disable navigation on WinForm with arrows in C#?

          【讨论】:

            【解决方案10】:
            protected override bool IsInputKey(Keys keyData)
            {
                if (((keyData & Keys.Up) == Keys.Up)
                    || ((keyData & Keys.Down) == Keys.Down)
                    || ((keyData & Keys.Left) == Keys.Left)
                    || ((keyData & Keys.Right) == Keys.Right))
                    return true;
                else
                    return base.IsInputKey(keyData);
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2023-03-15
              • 2016-10-07
              • 1970-01-01
              • 2013-12-08
              • 1970-01-01
              • 2016-04-01
              • 1970-01-01
              • 2011-11-21
              相关资源
              最近更新 更多