【问题标题】:KeyEvents on Form only works in combination with CTRL表单上的 KeyEvents 仅与 CTRL 结合使用
【发布时间】:2011-01-08 14:27:58
【问题描述】:

代码:

Private Sub KeyHandling(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
    Select Case e.KeyCode
      Case Keys.Left
        btnPrev.PerformClick()
      Case Keys.Right
        btnNext.PerformClick()
      Case Keys.Up
        btnFirst.PerformClick()
      Case Keys.Down
        btnLast.PerformClick()
    End Select
End Sub

我的表单的 KeyPreview 属性已启用。

问题:

这段代码不会做任何事情,除非我按住控制键。谁能解释一下? :)

【问题讨论】:

    标签: .net vb.net winforms keyevent


    【解决方案1】:

    这是因为光标键在 KeyDown 事件触发之前被提前拦截。 Winforms 使用它来移动焦点,就像 Tab 一样。当您按住 Ctrl 键时,它不再是导航键,您的 KeyDown 事件可以看到它。

    您通常可以通过覆盖 IsInputKey() 来解决这个问题,但如果表单有任何控件,这将不起作用。如果您将 KeyPreview 设置为 true,他们可能会这样做。表单永远不会获得焦点,控件会。您需要放弃 KeyPreview,无论如何它都是旧的 VB6 时代错误,您可以通过覆盖 ProcessCmdKey() 来捕获光标键。像这样:

    Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, ByVal keyData As System.Windows.Forms.Keys) As Boolean
        If keyData = Keys.Left Then
            Console.WriteLine("left")
            Return True
        End If
        Return MyBase.ProcessCmdKey(msg, keyData)
    End Function
    

    【讨论】:

      【解决方案2】:

      我假设您的表单上有按钮。当按钮具有焦点时,用户可以通过使用表单上按钮之间的箭头按钮导航来更改焦点。这就是为什么在按下箭头键时按钮不会收到 KeyDown 事件的原因。

      以下技巧将帮助您避免这种情况。对于表单上的每个按钮,将 PreviewKeyDown 事件设置为:

      Private Sub Button1_PreviewKeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PreviewKeyDownEventArgs) Handles Button1.PreviewKeyDown
              e.IsInputKey = True
      End Sub
      

      【讨论】:

      • 这可能有效,但如果可能的话,您应该在容器控件的更高级别上真正处理这个问题。它使代码更加优雅和可维护。
      【解决方案3】:

      发生的情况是箭头键在表单上的控件中导航,很像 Tab 键。每次按下箭头键都会将焦点从当前活动的控件移动到与该箭头键相同的相对方向的下一个控件。

      这种对箭头键的解释是在比您正在处理的表单的KeyDown 事件更高的级别上实现的。每个按键实际上都被ProcessDialogKey function 消耗,这会阻止该按键事件被传递给您的KeyHandling 方法以进行任何进一步的处理。

      Ctrl 键被按住时,一切都按预期工作的原因是 ProcessDialogKey 函数不会消耗这些事件,从而允许将它们传递给您的事件处理程序方法.该方法的documentation 告诉我们:

      该方法不对包含 ALT 或 CONTROL 修饰符的击键执行任何处理。


      如果您不希望箭头键在控件之间导航而只是“单击”恰当命名的按钮,则解决方案应该很明显:您需要覆盖 ProcessDialogKey 方法,添加自定义键处理逻辑,并且返回值“True”表示您自己处理了密钥。否则,您将继续调用基类,以免破坏诸如 TabEnter 之类的标准处理。同样,documentation 在这里非常清晰:

      在派生类中重写ProcessDialogKey 方法时,控件应返回true 以指示它已处理密钥。对于没有被控件处理的键,应该返回调用基类的ProcessDialogChar方法的结果。

      只需将以下代码添加到您的表单中,然后删除您现在拥有的 KeyHandling 方法:

      Protected Overrides Function ProcessDialogKey(ByVal keyData As System.Windows.Forms.Keys) As Boolean
          Select Case keyData
              Case Keys.Left
                  btnPrev.PerformClick()
                  Return True
              Case Keys.Right
                  btnNext.PerformClick()
                  Return True
              Case Keys.Up
                  btnFirst.PerformClick()
                  Return True
              Case Keys.Down
                  btnLast.PerformClick()
                  Return True
          End Select
      
          Return MyBase.ProcessDialogKey(keyData)
      End Function
      

      【讨论】:

        【解决方案4】:

        您需要提供更多信息。

        首先,您正在处理哪个表单事件。您显示一个具有非标准处理程序名称的处理程序,但您没有显示它与哪个事件相关联。您如何将其与事件关联?

        在表单设计器中,查看“属性”窗口中的事件选项卡。您在 KeyDown 或 KeyPress 下有任何内容吗?这就是它需要的地方。

        第二,它没有做任何事情是因为你没有连接它来形成键盘事件,还是因为它运行但没有做你想做的事?设置断点。代码是否被调用过?

        根据上述问题的答案,您可能需要在处理 KeyDown 或 KeyPress 事件之间切换,具体取决于您要检测的字符。

        【讨论】:

        • 您必须滚动才能看到它,但方法声明的最后会告诉您它正在处理什么事件:Handles Me.KeyDown。它已经为该方法进行了适当的连接。你必须检查标签——这不是 C#。
        • @Code:啊,是的,我习惯了 C# 并且没有向右滚动。谢谢。
        猜你喜欢
        • 2022-08-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-27
        • 1970-01-01
        • 2019-10-30
        • 1970-01-01
        相关资源
        最近更新 更多