【问题标题】:Create keyboard shortcuts using a combination of 2 Keys使用 2 个键的组合创建键盘快捷键
【发布时间】:2021-07-19 20:59:22
【问题描述】:

例如,当在我的主窗体中按下25 键时,Form1 应该会打开。 按下时,例如2a,应打开Form2

Private Sub Form1_KeyPress(sender As Object, e As KeyPressEventArgs) Handles Me.KeyPress
    Dim q As Queue(Of string) = New Queue(Of string)()
    q.Enqueue(e.keychar)  
    q.Enqueue(e.keychar)
    For Each element As string In q
        If element = "25" Then
            Form2.Show()
            If element = "2a" Then
                Form3.Show()
            End If
        End If
    Next
End Sub

【问题讨论】:

  • 只有 ONE 键。你怎么能得到2a,这是两个值?这是十六进制表示法,还是您想在两个按键事件中进行检查?
  • 我想通过两个按键事件来检查这个,如果正确显示我的表单,我想与单词进行比较
  • 您可能需要重新考虑您的组合键。你有主表格吗?如果是这样,请将MenuStrip 添加到主窗体。然后添加一个名为“Forms”的 ToolStripMenuItem。在属性中,设置Visible=false。在“Forms”(在菜单中)下,添加“Form 1”、“Form 2”等。在 MenuStrip 中,选择“Form 1”。在属性中,设置ShowShortcutKeys = True,然后点击ShortcutKeys并选择所需的组合键打开Form1。对其他表单重复此操作。

标签: .net vb.net winforms keyboard-shortcuts


【解决方案1】:

您应该使用 Microsoft 的响应式框架(又名 Rx)- NuGet System.Reactive.Windows.Forms 并添加 Imports System.Reactive.Linq - 然后您可以这样做:

Public Class Main
    Protected Overrides Sub OnLoad(e As EventArgs)
        MyBase.OnLoad(e)

        Dim factories = New Dictionary(Of String, Func(Of Form))() From
            {
                {"25", Function() New Form1()},
                {"2a", Function() New Form2()}
            }

        _subscription =
            Observable. 
                FromEventPattern(Of KeyPressEventHandler, KeyPressEventArgs)(
                    Sub(h) AddHandler Me.KeyPress, h,
                    Sub(h) RemoveHandler Me.KeyPress, h). 
                Buffer(2).
                Select(Function(x) New String(x.[Select](Function(y) y.EventArgs.KeyChar).ToArray())).
                Where(Function(x) factories.ContainsKey(x)). 
                ObserveOn(Me).
                Select(Function(x) factories(x).Invoke()).
                Subscribe(Sub(f) f.Show())
    End Sub

    Private _subscription As IDisposable = Nothing
End Class

现在您可以在 factories 字典中添加任意数量的密钥对。

关闭表单时只需致电_subscription.Dispose() 进行清理。

【讨论】:

  • 很高兴您为该线程做出了贡献,但语法看起来像是 TypeScript、C# 和 Visual Basic 的混搭。我非常固执的看法是,你不仅过度设计了一个解决方案,而且还让它几乎不可读。我是那种更喜欢 LINQ 风格的语法而不是传统循环机制的人。
  • 感谢您的解决方案。我使用的是 2010 版,没有 Imports System.Reactive.Linq 请帮帮我
  • @mostafabarzegar - 您需要 NuGet System.Reactive.Windows.Forms,然后将 Imports System.Reactive.Linq 添加到代码顶部。
  • @David - 让我们把责任归咎于 VB.NET 中 lambda 的语法。与 C# 语法相比,它很糟糕。我当然理解为什么 VB 开发人员会认为它是“TypeScript、C# 和 Visual Basic 的混搭”。
  • 我不再做太多的 VB.NET 开发,实际上主要是 C# 和 Angular,我只是说你的解决方案不必要地过度设计;更不用说您可以使用查询样式语法来显着提高可读性而不牺牲性能。
【解决方案2】:

按照使用队列的逻辑(也许这就是您需要使用的),您可以构建一个类对象来处理这些按键并在找到已知组合时执行操作。

我正在使用Dictionary(Of Integer, Action) 来存储Keys 组合并将Action 映射到每个组合。
如果找到组合键,则调用 Action?.Invoke(),以创建 Form 类的新实例。

为了在您使用的表单中按下按键,我将覆盖ProcessCmdKey。每当按下 Key 时都会调用此方法。请注意,所有键都被拦截,包括那些定向到子控件的键。
因此,如果您在 TextBox 中写入,例如 25Form1 将打开。
如果这不是您想要的,请添加一个布尔字段,当可写子控件接收到焦点时禁用键处理。

Public Class MainForm
    Private keyPressHandler As New DoubleKeyPressHandler()

    Protected Overrides Function ProcessCmdKey(ByRef msg As Message, keyData As Keys) As Boolean
        keyPressHandler.Add(keyData)
        Return MyBase.ProcessCmdKey(msg, keyData)
    End Function
End Class

您可以添加新的操作(例如,添加打开 Form43M 组合):

keyPressHandler.Actions.Add(Keys.D3 << 16 Or Keys.M, Sub() Call New Form4().Show()) 

DoubleKeyPressHandler 助手类:

该类将每个键组合视为整数的高/低 16 位部分,因此一个键占据高位字(从 16 到 31 位)另一个是低位字(位从 0 到 15)。

如果您不想缓存不匹配组合的第二次按键,则只能使用 Dim dKey = keyQueue.Dequeue &lt;&lt; 16 Or keyQueue.Dequeue
在这种情况下,还要删除TryMapKeys() 中的Else 块。

Friend Class DoubleKeyPressHandler
    Private keyQueue As New Queue(Of Keys)
    Public Sub New()
        Actions = New Dictionary(Of Integer, Action) From {
            {Keys.D2 << 16 Or Keys.D5, Sub() Call New Form1().Show()},
            {Keys.D2 << 16 Or Keys.A, Sub() Call New Form2().Show()}
        }
    End Sub

    Public ReadOnly Actions As Dictionary(Of Integer, Action)

    Public Sub Add(key As Keys)
        keyQueue.Enqueue(key)
        TryMapKeys()
    End Sub

    Private Sub TryMapKeys()
        If keyQueue.Count < 2 Then Return
        Dim key1 = keyQueue.Dequeue
        Dim key2 = keyQueue.Dequeue
        Dim dKey = key1 << 16 Or key2
        Dim keyAction As Action = Nothing
        If Actions.TryGetValue(dKey, keyAction) Then
            keyAction?.Invoke()
        Else
            ' If the combination is not a match, the last Key is added back
            ' Remove the Else block if you prefer to cancel it instead. Test it.
            keyQueue.Enqueue(key2)
        End If
    End Sub
End Class

【讨论】:

  • 您应该选择一个答案并将其标记为 good one(您喜欢的那个),这样它就会关闭 issue。跨度>
【解决方案3】:

您的代码有几个问题:

  1. 您将相同的 keychar 添加到集合中两次
  2. 因为集合是在 KeyPress 范围内定义的,所以下次触发事件时它将为空
  3. 您正在迭代集合并检查当前迭代的值是否等于两个不同的值(这永远不会是真的)
  4. 您正在将 Char 值与 String 值进行比较(这永远不会是真的)
  5. KeyChars 表示 ASCII 字符,但看起来你想比较十六进制值

您想要做什么并不是很明显,但是如果您想在 keychar 等于百分号字符时显示Form2 或在 keychar 等于星号字符时显示Form3,然后删除您当前拥有的所有内容并只使用一个简单的 If/Then:

Private Sub Form1_KeyPress(sender As Object, e As KeyPressEventArgs) Handles Me.KeyPress
    If e.KeyChar = "%"c Then
        Form2.Show()
    ElseIf e.KeyChar = "*"c Then
        Form3.Show()
    End If
End Sub

【讨论】:

  • 我想在我按下键 2 再按下 a 时显示 form3,它结合了 2a
  • 你能帮我吗,因为我是初学者
  • 您期望什么样的打字员?如果有人按“2”,然后走开,几分钟后又回来按“a”,这样可以吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-31
  • 1970-01-01
  • 2022-01-02
相关资源
最近更新 更多