表单上的 KeyEvents 只能与 CTRL 结合使用

发布于 2024-10-11 07:50:15 字数 493 浏览 5 评论 0原文

代码:

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 属性已启用。

问题:

除非我按住控制键,否则此代码不会执行任何操作。谁能解释一下吗? :)

Code:

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

The KeyPreview property of my form is enabled.

Problem:

This code won't do anything, except when I hold the control key. Can anyone explain this? :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

小矜持 2024-10-18 07:50:15

这是因为光标键在 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

This is because the cursor keys get intercepted early, before the KeyDown event fires. Winforms uses it to move the focus, just like Tab. When you hold down the Ctrl key, it is no longer a navigating key and your KeyDown event can see it.

You'd normally fix that by overriding IsInputKey() but that won't work if the form has any controls. They probably do if you set KeyPreview to true. The form never gets the focus, the controls do. You need to give up on KeyPreview, it's an old VB6 anachronism anyway, you catch the cursor keys by overriding ProcessCmdKey(). Like this:

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
羁〃客ぐ 2024-10-18 07:50:15

我假设您的表单上有按钮。当按钮具有焦点时,用户可以通过使用表单上按钮之间的箭头按钮进行导航来更改焦点。这就是为什么按下箭头键时按钮不会收到 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

I assume you have Buttons on your form. When a button has the focus the user can change the focus by navigate with the arrow buttons between the buttons on the form. That is the reason why buttons don't receive the KeyDown event when an arrow key is pressed.

Following trick will help you to avoid this. For every button on your form set the PreviewKeyDown event to the following:

Private Sub Button1_PreviewKeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PreviewKeyDownEventArgs) Handles Button1.PreviewKeyDown
        e.IsInputKey = True
End Sub
心的位置 2024-10-18 07:50:15

发生的情况是箭头键正在浏览表单上的控件,非常类似于 Tab 键。每次按箭头键都会将焦点从当前活动的控件移动到与该箭头键相同的相对方向的下一个控件。

箭头键的这种解释是在比您正在处理的表单的 KeyDown 事件更高的级别上实现的。每次按键实际上都被 ProcessDialogKey 函数,它阻止该按键事件被传递到您的 KeyHandling 方法进行任何进一步的处理。

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

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

如果您不希望箭头键在控件之间导航,而只想“单击”适当命名的按钮,那么解决方案应该是显而易见的:您需要重写 ProcessDialogKey 方法,添加您的自定义密钥处理逻辑,并返回值“True”以指示您自己处理了密钥。否则,您将继续调用基类,以免破坏 TabEnter 等内容的标准处理。同样,文档非常清晰这里:

当重写派生类中的 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

What's happening is that the arrow keys are navigating the controls on the form, much like the Tab key. Each press of an arrow key is moving the focus from the currently active control to the next control in the same relative direction as that arrow key.

This interpretation of arrow keys is implemented at a higher level than the form's KeyDown event that you're handling. Each key press is actually being consumed by the ProcessDialogKey function, which is preventing that key event from ever being passed down to your KeyHandling method for any further processing.

The reason that everything works as you expect when the Ctrl key is held down is that the ProcessDialogKey function doesn't consume those events, allowing them to be passed on to your event handler method. The method's documentation tells us:

The method performs no processing on keystrokes that include the ALT or CONTROL modifiers.

If you don't want the arrow keys to navigate between your controls and only to "click" the aptly-named buttons, the solution should be obvious: You need to override the ProcessDialogKey method, add your custom key handling logic, and return a value of "True" to indicate that you processed the key yourself. Otherwise, you'll go ahead and call through to the base class so as not to disrupt the standard handling of things like Tab and Enter. Again, the documentation is refreshingly clear here:

When overriding the ProcessDialogKey method in a derived class, a control should return true to indicate that it has processed the key. For keys that are not processed by the control, the result of calling the base class's ProcessDialogChar method should be returned.

Simply add the following code to your form, and remove the KeyHandling method you have now:

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
≈。彩虹 2024-10-18 07:50:15

您需要提供更多信息。

对于初学者来说,您正在处理哪个表单事件。您显示具有非标准处理程序名称的处理程序,但不显示它与哪个事件关联。您如何将其与事件关联起来?

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

其次,它是否没有执行任何操作,因为您没有将其连接到形成键盘事件,或者因为它运行但没有执行您想要的操作?设置断点。代码会被调用吗?

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

You need to provide a lot more information.

For starters, which form event are you handling. You show a handler with a non-standard handler name, but you don't show which event it is associated with. How are you associating it with an event?

In the form designer, look at the events tab in the Properties window. Do you have anything under KeyDown or KeyPress? That's where it needs to be.

Second, is it not doing anything because you don't have it hooked up to form keyboard events or because it runs but just doesn't do what you want? Set a breakpoint. Does the code ever get called?

Depending on the answer to the questions above, you may need to switch between handling the KeyDown or KeyPress event, depending on which characters you are trying to detect.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文