我有一个带有ActiveX控件的MS Word表单(不是表单控件)。假设我有两个文本框和两个选项按钮,如下所示:
Name: [textBox1]
Address: [textBox2]
Gender: [opt1] Male [opt2] Female
现在,如果我想按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
现在,在我的真实表单中,有20个文本框和12个选项按钮,因此为每个表单字段写下keydown事件非常无聊。我该如何编写一个宏,以便它首先在keydown上获取当前表单字段的名称(并将其验证为tab keydown),然后转到下一个表单字段?
为了制表符顺序,我将按时间顺序重命名所有表单域,例如field1,field2,field3 .........,等等,这样,随着代码的增加,代码可以将制表符移至下一个表单字段。
这是我在表单中使用的ActiveX工具的屏幕截图:
我也有cross-posted this topic到VbaExpress论坛。
答案 0 :(得分:2)
与我上次回答相比,您不会比这个问题更快乐。
问题在于,按键或KeyDown仅由焦点位于ActiveX控件中的事实触发,并且将特定于该控件。因此,除了每个控件的KeyDown事件之外,您别无选择。您可以将事件中的代码保持最少,但是...
无法通过名称直接将文档表面上的控件标识为 string 。 ThisDocument.ControlName
是可能的,但是没有类似ThisDocument.Controls(“ ControlName”)的东西可以让您替换名称,也不允许您标识当前控件的名称。
有一种方法可以做到,但是令人费解。由于这些文本与文本一致(无文本换行),因此它们属于文档的InlineShapes
集合。它们的编程接口只能通过InlineShape的OLEFormat.Object
属性来解决。这意味着代码需要循环InlineShapes集合两次:一次标识按下键的ActiveX控件,一次标识下一个控件。
以下代码说明了原理。它不所做的是
请注意,可能 可以绕开每个控件的事件代码。它将涉及使用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
总而言之,坚持旧版表单字段或内容控件,或者将其移至UserForm,然后再写入文档,可能更有意义。