例如,当在我的主窗体中按下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
您应该使用Microsoft的Reactive Framework(又名Rx(-NuGetSystem.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()
进行清理即可。
遵循使用队列的逻辑(也许这就是您需要使用的(,您可以构建一个处理这些按键的类对象,并在找到已知组合时执行Action。
我使用Dictionary(Of Integer, Action)
来存储Keys
组合,并将Action映射到每个组合
如果找到键的组合,则调用Action?.Invoke()
,以创建Form类的新实例。
为了在用于此操作的窗体中按下键,我将覆盖ProcessCmdKey。每当按下键时都会调用此方法。请注意,所有密钥都被拦截,包括指向子控件的密钥
因此,如果您在TextBox中写入例如25
,则会打开Form1
如果这不是您想要的,请添加一个布尔字段,当可写子控件接收到焦点时,该字段将禁用密钥处理。
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
您可以添加新操作(例如,添加打开Form4
的3M
组合(:
keyPressHandler.Actions.Add(Keys.D3 << 16 Or Keys.M, Sub() Call New Form4().Show())
DoubleKeyPressHandler
辅助类:
该类将键的每个组合视为整数的高/低16位部分,因此一个键占用高位字(从16到31的位(,另一个键占用低位字(从0到15的位(。
如果您不想缓存不匹配组合的第二次按键,则只能使用Dim dKey = keyQueue.Dequeue << 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
您的代码有几个问题:
- 您将同一个keychar添加到集合中两次
- 因为集合是在KeyPress的范围内定义的,所以下次触发事件时它将为空
- 您正在对集合进行迭代,并检查当前迭代的值是否等于两个不同的值(这永远不会是真的(
- 您正在将Char值与String值进行比较(这永远不会为真(
- 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