vba - 如何通过 MS Word 中的宏设置 Tab 键顺序?
问题描述
我有一个带有 ActiveX 控件(不是表单控件)的 MS Word 表单。假设我有两个文本框和两个选项按钮,如下所示:
Name: [textBox1]
Address: [textBox2]
Gender: [opt1] Male [opt2] Female
现在,如果我想要一个标签顺序,我必须添加以下宏:
Private Sub textBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
If KeyCode = 9 Then
textBox2.Activate
End If
End Sub
Private Sub textBox2_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
If KeyCode = 9 Then
opt1.Activate
End If
End Sub
Private Sub opt1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
If KeyCode = 9 Then
opt2.Activate
End If
End Sub
现在在我的真实表单中,有 20 个文本框和 12 个选项按钮,因此为每个表单字段写下 keydown 事件是很无聊的。如何编写一个宏,以便它首先在 keydown 上获取当前表单字段的名称(并将其验证为 tab keydown),然后转到下一个表单字段?
为了标签顺序,我将按时间顺序重命名所有表单字段,例如 field1、field2、field3 ......等,这样代码可以将标签移动到下一个表单字段。
这是我在表单中使用的 ActiveX 工具的屏幕截图:
我也将此主题交叉发布到 VbaExpress 论坛。
解决方案
你对这个答案不会比我上一个答案更快乐......
问题是按键或 KeyDown 仅由焦点位于ActiveX 控件中这一事实触发,并且特定于该控件。因此,您别无选择,只能为每个控件设置一个 KeyDown 事件。您可以将事件中的代码保持在最低限度,但是...
无法直接通过名称作为字符串来识别文档表面上的控件。ThisDocument.ControlName
是可能的,但是没有像 ThisDocument.Controls("ControlName") 这样的东西可以让您替换名称,也不允许您识别当前控件的名称。
有一种方法可以做到这一点,但它很复杂。由于这些与文本内联(没有文本换行)它们属于文档的InlineShapes
集合。它们的编程接口只能通过 InlineShape 的OLEFormat.Object
属性来处理。这意味着代码需要循环 InlineShapes 集合两次:一次识别按下键的 ActiveX 控件,一次识别应该下一个的控件。
下面的代码说明了这个原理。它不做的是
- 适用于超过 9 个控件 - 这需要代码从名称的右侧检查有多少个字符是数字
- 如果焦点在最后一个控件,则返回第一个控件
请注意,有可能绕过每个控件的事件代码。它将涉及使用 Windows API,这意味着每次用户按下 Tab 时都会触发。但是我不知道当焦点在控件内时是否会捕获按键。如果是这种情况,您每次都必须进行测试 - 而且您仍然必须能够确定焦点在哪个控件中。
Private Sub TextBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
GoToNextControl KeyCode, ThisDocument.TextBox1.Name
End Sub
Private Sub TextBox2_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
GoToNextControl KeyCode, ThisDocument.TextBox2.Name
End Sub
Sub GoToNextControl(KeyCode As MSForms.ReturnInteger, controlName As String)
Dim ils As Word.InlineShape, ils2 As Word.InlineShape
Dim c As MSForms.Control
Dim baseName As String, nextName
Dim nameCounter As Long
baseName = Mid(controlName, 1, Len(controlName) - 1)
nameCounter = Right(controlName, 1)
If KeyCode = 9 Then
For Each ils In ThisDocument.InlineShapes
If ils.Type = wdInlineShapeOLEControlObject Then
If ils.OLEFormat.Object.Name = controlName Then
nextName = baseName & nameCounter + 1
For Each ils2 In ThisDocument.InlineShapes
If ils2.Type = wdInlineShapeOLEControlObject Then
If ils2.OLEFormat.Object.Name = nextName Then
ils2.Select
Exit Sub
End If
End If
Next
End If
End If
Next
End If
End Sub
总而言之,坚持遗留表单字段或内容控件可能更有意义,或者将其移动到然后写入文档的用户表单。
推荐阅读
- python - Adobe After Effects COM 对象模型 ID?
- python - 在 Windows 上从 python 运行星露谷物语
- php - Laravel 审计方法审计不存在
- python - Python:如何根据函数是否匹配分配的字符串来获取函数
- javascript - 多月日期选择器
- nginx - Proxy_pass 忽略端口
- c# - 打开文件并用新行c#连续读取文件?
- javascript - Discord Js - 不同的线条
- python - 澄清 Python 教程文档中的一段
- c# - DataGridComboBox 与嵌套的 ReactiveList 绑定
目的