在焦点文本框和 DataGridView 单元格上使用虚拟键盘
Use a virtual Keyboard on focused Textboxes and DataGridView Cells
在我的表单中,我有各种文本框,我使用按钮创建的表单键盘写入这些文本框。我在 Form.Load 中有这段代码,它使用事件处理程序来确定哪个文本框具有焦点:
For Each control As Control In Me.Controls
If control.GetType.Equals(GetType(TextBox)) Then
Dim textBox As TextBox = control
AddHandler textBox.Enter, Sub() FocussedTextbox = textBox
End If
Next
然后我用这个在每个按钮上写一个特定的字符:
Private Sub btnQ_Click(sender As Object, e As EventArgs) Handles btnQ.Click
If btnQ.Text = "Q" Then
FocussedTextbox.Text += "Q"
ElseIf btnQ.Text = "q" Then
FocussedTextbox.Text += "q"
End If
End Sub
到那时我还不错,一切都按预期进行。问题是我也有一个 DataGridView
我想写入但不能像在文本框上那样专注于选定的单元格。
我试过这个:
For Each control As Control In Me.Controls
If control.GetType.Equals(GetType(TextBox)) Then
Dim textBox As TextBox = control
AddHandler textBox.Enter, Sub() FocussedTextbox = textBox
ElseIf control.GetType.Equals(GetType(DataGridViewCell)) Then
Dim DGVC As DataGridView = control
AddHandler DGVC.CellBeginEdit, Sub() FocussedTextbox = DGVC
End If
Next
但它只选择了我的最后一个文本框。
我将变量 FocussedTextbox
声明为 Control
所以它不是特定于文本框而是任何控件。
任何帮助将不胜感激。
要使用按钮将文本添加到当前 ActiveControl,这些按钮不得从 ActiveControl 窃取焦点(否则它们将成为 ActiveControl)。
这样,您还可以避免所有这些 FocusedTextbox = textBox
等并删除该代码。
您只需要没有设置 Selectable 属性的按钮。您可以使用派生自 Button 的自定义控件并删除 ControlStyles.Selectable in its constructor using the SetStyle 方法:
Public Class ButtonNoSel
Inherits Button
Public Sub New()
SetStyle(ControlStyles.Selectable, False)
End Sub
End Class
用这个按钮替换您的按钮(或者,如果您已经在使用自定义控件,则只需设置样式)。
要用此自定义控件替换现有按钮:
- 向您的项目添加一个新的 class 对象,将其命名为
ButtonNoSel
,将上面的所有代码复制到新的 class 中,以替换您在其中找到的两行代码。
- 构建项目。您现在可以在工具箱中找到
ButtonNoSel
控件。用这个替换你的按钮。
- 或者,打开 Form 的 Designer 文件并将 (CTRL+H) 所有与虚拟键盘相关的
System.Windows.Forms.Button()
替换为 ButtonNoSel
。
- 删除现有的事件处理程序,不再需要这些。
在托管这些按钮(表单或您正在使用的任何其他内容)的 class 的构造函数中添加相同的 Click 事件处理程序。
然后,您可以删除所有这些事件处理程序,每个控件一个,您现在拥有;所有人只需要一个事件处理程序:
Public Sub New()
InitializeComponent()
For Each ctrl As Control In Me.Controls.OfType(Of ButtonNoSel)
AddHandler ctrl.Click, AddressOf KeyBoardButtons_Click
Next
End Sub
当然,您也不需要向任何其他控件添加事件处理程序,这就是所需的全部内容。
现在,您可以过滤希望键盘使用的控件类型,例如,TextBoxBase
控件(TextBox 和 RichTextBox)、DataGridView、NumericUpDown 等
或者仅过滤需要 特殊处理 的特殊情况(例如,MonthCalendar)。
要添加与按下的按钮对应的字符,可以使用SendKeys.Send():它将在当前插入点插入新字符,因此您不需要任何其他代码来存储和重置caret/cursor 设置控件的文本 属性 时出现的位置。
在这个例子中,我正在检查 ActiveControl
是否是一个 TextBoxBase
控件,然后只发送被点击的按钮包含的字符。
如果是DataGridView,先发送F2
进入编辑模式,再发送char.
您也可以只发送一个字符(这样就不需要过滤器),但在这种情况下,您将替换而不是添加到该 Cell 的现有值。
Private Sub KeyBoardButtons_Click(sender As Object, e As EventArgs)
Dim selectedButton = DirectCast(sender, Control)
Dim keysToSend = String.Empty
If TypeOf ActiveControl Is TextBoxBase Then
keysToSend = selectedButton.Text
ElseIf TypeOf ActiveControl Is DataGridView Then
Dim ctrl = DirectCast(ActiveControl, DataGridView)
If TypeOf ctrl.CurrentCell IsNot DataGridViewTextBoxCell Then Return
SendKeys.Send("{F2}")
keysToSend = selectedButton.Text
Else
' Whatever else
End If
If Not String.IsNullOrEmpty(keysToSend) Then
SendKeys.Send(keysToSend)
End If
End Sub
► 请注意 {F2}
仅发送一次:当单元格进入编辑模式时,ActiveControl
是 DataGridViewTextBoxEditingControl
,因此一个 TextBox 控件,由 TextBoxBase
过滤器处理。
这是它的工作原理(仅使用此处发布的代码):
在我的表单中,我有各种文本框,我使用按钮创建的表单键盘写入这些文本框。我在 Form.Load 中有这段代码,它使用事件处理程序来确定哪个文本框具有焦点:
For Each control As Control In Me.Controls
If control.GetType.Equals(GetType(TextBox)) Then
Dim textBox As TextBox = control
AddHandler textBox.Enter, Sub() FocussedTextbox = textBox
End If
Next
然后我用这个在每个按钮上写一个特定的字符:
Private Sub btnQ_Click(sender As Object, e As EventArgs) Handles btnQ.Click
If btnQ.Text = "Q" Then
FocussedTextbox.Text += "Q"
ElseIf btnQ.Text = "q" Then
FocussedTextbox.Text += "q"
End If
End Sub
到那时我还不错,一切都按预期进行。问题是我也有一个 DataGridView
我想写入但不能像在文本框上那样专注于选定的单元格。
我试过这个:
For Each control As Control In Me.Controls
If control.GetType.Equals(GetType(TextBox)) Then
Dim textBox As TextBox = control
AddHandler textBox.Enter, Sub() FocussedTextbox = textBox
ElseIf control.GetType.Equals(GetType(DataGridViewCell)) Then
Dim DGVC As DataGridView = control
AddHandler DGVC.CellBeginEdit, Sub() FocussedTextbox = DGVC
End If
Next
但它只选择了我的最后一个文本框。
我将变量 FocussedTextbox
声明为 Control
所以它不是特定于文本框而是任何控件。
任何帮助将不胜感激。
要使用按钮将文本添加到当前 ActiveControl,这些按钮不得从 ActiveControl 窃取焦点(否则它们将成为 ActiveControl)。
这样,您还可以避免所有这些 FocusedTextbox = textBox
等并删除该代码。
您只需要没有设置 Selectable 属性的按钮。您可以使用派生自 Button 的自定义控件并删除 ControlStyles.Selectable in its constructor using the SetStyle 方法:
Public Class ButtonNoSel
Inherits Button
Public Sub New()
SetStyle(ControlStyles.Selectable, False)
End Sub
End Class
用这个按钮替换您的按钮(或者,如果您已经在使用自定义控件,则只需设置样式)。
要用此自定义控件替换现有按钮:
- 向您的项目添加一个新的 class 对象,将其命名为
ButtonNoSel
,将上面的所有代码复制到新的 class 中,以替换您在其中找到的两行代码。 - 构建项目。您现在可以在工具箱中找到
ButtonNoSel
控件。用这个替换你的按钮。 - 或者,打开 Form 的 Designer 文件并将 (CTRL+H) 所有与虚拟键盘相关的
System.Windows.Forms.Button()
替换为ButtonNoSel
。 - 删除现有的事件处理程序,不再需要这些。
在托管这些按钮(表单或您正在使用的任何其他内容)的 class 的构造函数中添加相同的 Click 事件处理程序。
然后,您可以删除所有这些事件处理程序,每个控件一个,您现在拥有;所有人只需要一个事件处理程序:
Public Sub New()
InitializeComponent()
For Each ctrl As Control In Me.Controls.OfType(Of ButtonNoSel)
AddHandler ctrl.Click, AddressOf KeyBoardButtons_Click
Next
End Sub
当然,您也不需要向任何其他控件添加事件处理程序,这就是所需的全部内容。
现在,您可以过滤希望键盘使用的控件类型,例如,TextBoxBase
控件(TextBox 和 RichTextBox)、DataGridView、NumericUpDown 等
或者仅过滤需要 特殊处理 的特殊情况(例如,MonthCalendar)。
要添加与按下的按钮对应的字符,可以使用SendKeys.Send():它将在当前插入点插入新字符,因此您不需要任何其他代码来存储和重置caret/cursor 设置控件的文本 属性 时出现的位置。
在这个例子中,我正在检查 ActiveControl
是否是一个 TextBoxBase
控件,然后只发送被点击的按钮包含的字符。
如果是DataGridView,先发送F2
进入编辑模式,再发送char.
您也可以只发送一个字符(这样就不需要过滤器),但在这种情况下,您将替换而不是添加到该 Cell 的现有值。
Private Sub KeyBoardButtons_Click(sender As Object, e As EventArgs)
Dim selectedButton = DirectCast(sender, Control)
Dim keysToSend = String.Empty
If TypeOf ActiveControl Is TextBoxBase Then
keysToSend = selectedButton.Text
ElseIf TypeOf ActiveControl Is DataGridView Then
Dim ctrl = DirectCast(ActiveControl, DataGridView)
If TypeOf ctrl.CurrentCell IsNot DataGridViewTextBoxCell Then Return
SendKeys.Send("{F2}")
keysToSend = selectedButton.Text
Else
' Whatever else
End If
If Not String.IsNullOrEmpty(keysToSend) Then
SendKeys.Send(keysToSend)
End If
End Sub
► 请注意 {F2}
仅发送一次:当单元格进入编辑模式时,ActiveControl
是 DataGridViewTextBoxEditingControl
,因此一个 TextBox 控件,由 TextBoxBase
过滤器处理。
这是它的工作原理(仅使用此处发布的代码):