简体   繁体   English

如何通过MS Word中的宏设置制表符顺序?

[英]How to set tab order by a macro in MS Word?

I have a MS Word form with ActiveX control (not the form control). 我有一个带有ActiveX控件的MS Word表单(不是表单控件)。 Suppose I have two textboxes and two option button as follows: 假设我有两个文本框和两个选项按钮,如下所示:

Name: [textBox1]
Address: [textBox2]
Gender: [opt1] Male [opt2] Female

Now if I want a tab order, I have to add following macro: 现在,如果我想按Tab键排序,则必须添加以下宏:

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

Now in my real form there are 20 text boxes and 12 option buttons, so it is quite boring to write down keydown event for each form field. 现在,在我的真实表单中,有20个文本框和12个选项按钮,因此为每个表单字段写下keydown事件非常无聊。 How can I write a macro so that it will first get the name of current form field on keydown (and validating it as tab keydown) and then go to next form field? 如何编写宏,以便它首先在keydown上获取当前表单字段的名称(并将其验证为tab keydown),然后转到下一个form字段?

For the sake of tab order, I will then rename all form field chronologically such as field1, field2, field3......... etc, so that with an increment the code can move the tab to next form field. 为了制表符顺序,我将按时间顺序重命名所有表单域,例如field1,field2,field3 .........等,这样,随着代码的增加,代码可以将制表符移到下一个表单域。

Here is the screen shot of ActiveX tools those I used in forms: 这是我在表单中使用的ActiveX工具的屏幕截图:

在此处输入图片说明

I have cross-posted this topic to VbaExpress forum also. 我也将此主题交叉发布到VbaExpress论坛。

You aren't going to be any happier with this answer than you were with my last... 您得到的答案不会比我上一个更快乐...

The problem is that the keypress, or KeyDown, is only triggered by the fact that the focus is in an ActiveX control, and will be specific to that control. 问题在于,按键或KeyDown仅由焦点位于 ActiveX控件中的事实触发,并且将特定于该控件。 So you have no choice than a KeyDown event for every control. 因此,除了每个控件的KeyDown事件之外,您别无选择。 You can keep the code in the event to a minimum, but... 您可以将事件中的代码减至最少,但是...

There's no way to identify controls on a document surface directly by name as a string . 无法通过名称直接将文档表面上的控件标识为string ThisDocument.ControlName is possible, but there's nothing like ThisDocument.Controls("ControlName") available that would let you substitute names, nor allow you to identify the name of the current control. ThisDocument.ControlName ,但是没有类似ThisDocument.Controls(“ ControlName”)的名称可以替代名称,也不允许您标识当前控件的名称。

There is a way to do it, but it's convoluted. 有一种方法可以做到,但是令人费解。 Since these are in-line with the text (no text wrapping) they belong to the document's InlineShapes collection. 由于它们与文本一致(无文本换行),因此它们属于文档的InlineShapes集合。 Their programming interface can only be addressed through the InlineShape's OLEFormat.Object property. 它们的编程接口只能通过InlineShape的OLEFormat.Object属性进行寻址。 This means the code needs to loop the InlineShapes collection twice : once to identify the ActiveX control where the key was pressed, once to identify the control which should be next. 这意味着代码需要循环InlineShapes集合两次 :一次用于识别按下键的ActiveX控件,一次用于识别下一个控件。

The following code illustrates the principle. 以下代码说明了原理。 What it does not do is 什么它不会做的是

  • work for more than 9 controls - that would require code that checks, from the right of the name, how many characters are numerical 可用于9个以上的控件-这将需要代码从名称的右边检查数字中有多少个字符
  • go back to the first control if focus is in the last 如果焦点在最后一个,则返回第一个控件

Note that it might be possible to get around event code for each control. 请注意,有可能绕过每个控件的事件代码。 It would involve using the Windows API, which means it would fire every time the user presses Tab. 它将涉及使用Windows API,这意味着它将在用户每次按Tab 触发。 But I have no idea whether the key presses would be captured when focus is inside a control. 但是我不知道当焦点位于控件内部时是否会捕获按键。 And you would have to test each time if this is the case - and you'd still have to be able to identify which control the focus is in. 而且,如果是这种情况,则每次都必须进行测试-而且您仍然必须能够确定焦点所在的控件。

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

All-in-all it might make more sense to stick to the legacy form fields or to content controls, or move this to a UserForm that then writes to the document. 总而言之,坚持旧版表单字段或内容控件,或者将其移至UserForm,然后再写入文档,可能更有意义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM