首页 > 解决方案 > 如何通过 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 论坛。

标签: vbams-wordtab-ordering

解决方案


你对这个答案不会比我上一个答案更快乐......

问题是按键或 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

总而言之,坚持遗留表单字段或内容控件可能更有意义,或者将其移动到然后写入文档的用户表单。


推荐阅读