【问题标题】:Best way to implement keyboard shortcuts in a Windows Forms application?在 Windows 窗体应用程序中实现键盘快捷键的最佳方法?
【发布时间】:2010-09-28 20:16:24
【问题描述】:

我正在寻找实现常用 Windows 键盘快捷键的最佳方式(例如 Ctrl+FCtrl+ N) 在我的 C# 中的 Windows Forms 应用程序中。

应用程序有一个主窗体,它承载许多子窗体(一次一个)。当用户点击 Ctrl+F 时,我想显示一个自定义搜索表单。搜索表单将取决于应用程序中当前打开的子表单。

我正在考虑在 ChildForm_KeyDown 事件中使用类似的东西:

   if (e.KeyCode == Keys.F && Control.ModifierKeys == Keys.Control)
        // Show search form

但这不起作用。当您按下某个键时,该事件甚至不会触发。解决办法是什么?

【问题讨论】:

  • Winforms 似乎没有像原生 Windows API 这样的特定功能,这真的很奇怪。

标签: c# winforms keyboard-shortcuts


【解决方案1】:

您可能忘记将表单的KeyPreview 属性设置为True。覆盖ProcessCmdKey() 方法是通用解决方案:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
  if (keyData == (Keys.Control | Keys.F)) {
    MessageBox.Show("What the Ctrl+F?");
    return true;
  }
  return base.ProcessCmdKey(ref msg, keyData);
}

【讨论】:

  • 这很好用,但只有当表单是活动窗口时才会为我检测到它。任何人都知道如何绑定它,所以在任何窗口视图中都可以?
  • 在某些情况下KeyPreview是相当不可或缺的。例如,当需要按下快捷键来禁止输入但仍允许单独的MenuStrip 事件触发时。 ProcessCmdKey 方法会强制重复事件触发逻辑。
  • 嗯,不,Form 的 KeyDown 事件处理程序与菜单项的 Click 事件处理程序完全不同。您仍然可以执行完全相同的方法,或者直接调用事件处理程序方法(不需要由事件专门调用它)或将公共逻辑重构为单独的方法。
  • "什么是 Ctrl+F?"哈哈
【解决方案2】:

在主窗体上

  1. KeyPreview 设置为True
  2. 使用以下代码添加 KeyDown 事件处理程序

    private void MainForm_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Control && e.KeyCode == Keys.N)
        {
            SearchForm searchForm = new SearchForm();
            searchForm.Show();
        }
    }
    

【讨论】:

  • + for , Set KeyPreview to True .. 缺少那个
【解决方案3】:

最好的方法是使用菜单助记符,即在主窗体中设置菜单条目,并为其分配所需的键盘快捷键。然后其他一切都在内部处理,您所要做的就是实现在该菜单条目的Click 事件处理程序中执行的适当操作。

【讨论】:

  • 问题是主窗体不使用常见的窗口菜单。它使用用于显示子表单的自定义导航面板。通过单击子表单上的 ToolStripButton 来调用搜索表单。
  • menu mnemonics真实样本?
  • 助记符是与快捷键不同的概念,它们的操作方式有重要区别。简而言之,助记符是用于使用键盘访问菜单、菜单命令和对话框控件的下划线字符。 OTOH,快捷键是一种无需通过菜单即可访问命令的方式,而且它们可以是 Ctrl+F 或 F5 等任意键击,不限于字符键。
  • @Stewart 没错!我的回答并不是要暗示所有键盘快捷键都是助记符,只是菜单助记符是获得此功能的最简单方法。不幸的是,正如 Rockcoder 的评论所澄清的那样,这个解决方案在这里似乎并不合适。在可能的情况下,我仍然推荐它作为更好的解决方案。对于一般解决方案,Hans 接受的答案是前进的方向。
【解决方案4】:

你甚至可以试试这个例子:

public class MDIParent : System.Windows.Forms.Form
{
    public bool NextTab()
    {
         // some code
    }

    public bool PreviousTab()
    {
         // some code
    }

    protected override bool ProcessCmdKey(ref Message message, Keys keys)
    {
        switch (keys)
        {
            case Keys.Control | Keys.Tab:
              {
                NextTab();
                return true;
              }
            case Keys.Control | Keys.Shift | Keys.Tab:
              {
                PreviousTab();
                return true;
              }
        }
        return base.ProcessCmdKey(ref message, keys);
    }
}

public class mySecondForm : System.Windows.Forms.Form
{
    // some code...
}

【讨论】:

    【解决方案5】:

    如果您有菜单,那么更改 ToolStripMenuItemShortcutKeys 属性应该可以解决问题。

    如果没有,您可以创建一个并将其 visible 属性设置为 false。

    【讨论】:

    • 不,我没有菜单。用于搜索的 ToolStripButton 实际上位于 BindingNavigator 控件上,因此添加菜单可能不是一个选项。
    【解决方案6】:

    在主表单中,您必须:

    • 确保将 KeyPreview 设置为 true(默认为 TRUE)
    • 添加 MainForm_KeyDown(..) - 通过它您可以在此处设置所需的任何快捷方式。

    另外,我在谷歌上找到了这个,我想把这个分享给那些仍在寻找答案的人。 (全球)

    我认为你必须使用 user32.dll

    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
    
        if (m.Msg == 0x0312)
        {
            /* Note that the three lines below are not needed if you only want to register one hotkey.
             * The below lines are useful in case you want to register multiple keys, which you can use a switch with the id as argument, or if you want to know which key/modifier was pressed for some particular reason. */
    
            Keys key = (Keys)(((int)m.LParam >> 16) & 0xFFFF);                  // The key of the hotkey that was pressed.
            KeyModifier modifier = (KeyModifier)((int)m.LParam & 0xFFFF);       // The modifier of the hotkey that was pressed.
            int id = m.WParam.ToInt32();                                        // The id of the hotkey that was pressed.
    
    
            MessageBox.Show("Hotkey has been pressed!");
            // do something
        }
    }
    

    进一步阅读http://www.fluxbytes.com/csharp/how-to-register-a-global-hotkey-for-your-application-in-c/

    【讨论】:

      【解决方案7】:

      Hans's answer 对于新手来说可能会更容易一些,所以这是我的版本。

      您无需与KeyPreview 混淆,将其设置为false。要使用下面的代码,只需将其粘贴到您的 form1_load 下方并使用 F5 运行即可查看它的工作原理:

      protected override void OnKeyPress(KeyPressEventArgs ex)
      {
          string xo = ex.KeyChar.ToString();
      
          if (xo == "q") //You pressed "q" key on the keyboard
          {
              Form2 f2 = new Form2();
              f2.Show();
          }
      }
      

      【讨论】:

      • 首先,覆盖 ProcessCmdKey 是处理旨在执行某些类似命令的操作的击键的推荐方法,这是 OP 所要求的。其次,您误解了 Hans 关于将 KeyPreview 设置为 true 的评论;他只是在告诉 OP 为什么他的技术不起作用。使用 ProcessCmdKey 不需要将 KeyPreview 设置为 true。
      【解决方案8】:

      在 WinForm 中,我们总是可以通过以下方式获取 Control Key 的状态:

      bool IsCtrlPressed = (Control.ModifierKeys & Keys.Control) != 0;
      

      【讨论】:

        最近更新 更多