在运行时将用户窗体添加到不同的工作簿
Add userform to a different workbook at runtime
我打开了一个插件和一个工作簿。该插件是一个 .xlam 文件,我在工作簿中添加了对它的引用。插件受密码保护。
我的工作簿中的插件的 运行 public 方法是可能的。然而,插件中的一种方法利用 VBA.UserForms.Add
打开在 运行 时间 like this
创建的用户窗体
假设包含对 myAddin
的引用的工作簿具有以下内容:
Private Sub callAddin()
myAddin.ShowForm ThisWorkbook
End Sub
通常,我的插件中的代码如下所示:
Public Sub ShowForm(CallerWorkbook As Workbook)
Const vbext_ct_MSForm As Long = 3
'This is to stop screen flashing while creating form
Application.VBE.MainWindow.Visible = False
'Add to ThisWorkbook, not supplied workbook or VBE will crash - ignore CallerWorkbook
Dim myForm As Object
Set myForm = ThisWorkbook.VBProject.VBComponents.Add(vbext_ct_MSForm)
'Create the User Form
With myForm
.Properties("Caption") = "Select"
.Properties("Width") = 300
.Properties("Height") = 270
End With
'Show the form
Dim finalForm As Object
Set finalForm = VBA.UserForms.Add(myForm.Name)
finalForm.Show
'Remove form
ThisWorkbook.VBProject.VBComponents.Remove myForm
End Sub
效果很好。但是,当我的插件受密码保护时,不允许尝试向其添加临时用户表单。没问题,我只是将临时用户窗体添加到调用代码的工作簿中,因为这不会受到密码保护
Sub ShowForm(CallerWorkbook As Workbook)
Const vbext_ct_MSForm As Long = 3
'This is to stop screen flashing while creating form
Application.VBE.MainWindow.Visible = False
'Add to CallerWorkbook instead
Dim myForm As Object
Set myForm = CallerWorkbook.VBProject.VBComponents.Add(vbext_ct_MSForm)
'Create the User Form
With myForm
.Properties("Caption") = "Select"
.Properties("Width") = 300
.Properties("Height") = 270
End With
'Show the form
Dim finalForm As Object
'Now myForm cannot be found and added
Set finalForm = VBA.UserForms.Add(myForm.Name)
finalForm.Show
'Remove form
CallerWorkbook.VBProject.VBComponents.Remove myForm
End Sub
但是 VBA 似乎无法 看到 其中 myForm.Name
指向现在,因此 Add 方法失败 "Run time error 424: Object required"
有没有办法在另一个工作簿中显示在 运行 时间创建的表单?
您遇到的问题是默认情况下用户窗体是私有实例化的。这意味着一个项目不能引用另一个项目中的用户窗体,如果不能引用该窗体,则不能调用它的 Show
方法。
你的 Set myForm = CallerWorkbook.VBProject.VBComponents.Add(vbext_ct_MSForm)
语句 returns 是 VbComponent
,而不是 UserForm
,所以这就是你不能使用 VBA.UserForms.Add(myForm.Name)
[=32= 的原因]
有两种解决方法:
1 - 在您的加载项中创建一个 PublicNotCreatable
模板用户窗体
用户窗体就像 class,因此它可以设置 Instancing
属性,就像 class 一样。但是,VBE 不会在用户窗体的属性 Window 中公开 Instancing
属性,因此要设置实例化,您需要导出窗体,然后编辑 Attribute VB_Exposed
属性在文本编辑器中的 FRM 文件中,然后再次导入表单。以下是步骤:
- 在您的加载项项目中创建一个名为
TemplateForm
的用户窗体
- 删除
TemplateForm
并在删除之前选择导出表单
- 在文本编辑器中打开
TemplateForm.frm
文件
- 编辑
Attribute VB_Exposed = False
行,使其变为 Attribute VB_Exposed = True
- 将更改保存到
TemplateForm.frm
- 将
TemplateForm.frm
导入您的加载项
将 public 函数添加到您的外接程序 returns TemplateForm
的新实例。我已使此函数接受工作簿引用,以便加载项可以在表单上配置任何特定于工作簿的属性:
Public Function GetTemplateForm(CallerWorkbook As Workbook) As TemplateForm
Dim frm As TemplateForm
Set frm = New TemplateForm
'Set early-bound properties with intellisense
frm.Caption = "Select"
frm.Width = 300
frm.Height = 270
'Configure CallerWorkbook specific form properties here
'...
Set GetTemplateForm = frm
End Function
然后,您可以在用户的工作簿中显示 TemplateForm 的实例,而无需动态添加表单、处理屏幕闪烁或难以调试的代码:
Sub ShowAddinForm()
With MyAddin.GetTemplateForm(ThisWorkbook)
'Do more workbook specific propery setting here...
'...
.Show
End With
End Sub
** 注意 - Rubberduck VBA 加载项将很快能够添加 PublicNotCreatable
UserForm。
2 - 让加载项创建用户窗体组件,但让用户的工作簿管理它
这种方法远没有那么优雅。用户需要管理的代码多了很多,屏幕闪烁,代码难以调试。以下是步骤:
将此代码添加到加载项:
Public Function GetTempFormName(CallerWorkbook As Workbook) As String
Const vbext_ct_MSForm As Long = 3
'This is to stop screen flashing while creating form
Application.VBE.MainWindow.Visible = False
'Add to CallerWorkbook instead
With CallerWorkbook.VBProject.VBComponents.Add(vbext_ct_MSForm)
.Properties("Caption") = "Select"
.Properties("Width") = 300
.Properties("Height") = 270
GetTempFormName = .Name
End With
End Function
Public Sub RemoveTempForm(CallerWorkbook As Workbook, FormName As String)
With CallerWorkbook.VBProject.VBComponents
Dim comp As Object
Set comp = .Item(FormName)
.Remove .Item(FormName)
End With
End Sub
然后,在用户的工作簿中,添加以下代码:
Sub GetAddinToCreateForm()
Dim FormName As String
FormName = MyAddin.GetTempFormName(ThisWorkbook)
With VBA.UserForms.Add(FormName)
.Show
End With
MyAddin.RemoveTempForm ThisWorkbook, FormName
End Sub
我打开了一个插件和一个工作簿。该插件是一个 .xlam 文件,我在工作簿中添加了对它的引用。插件受密码保护。
我的工作簿中的插件的 运行 public 方法是可能的。然而,插件中的一种方法利用 VBA.UserForms.Add
打开在 运行 时间 like this
假设包含对 myAddin
的引用的工作簿具有以下内容:
Private Sub callAddin()
myAddin.ShowForm ThisWorkbook
End Sub
通常,我的插件中的代码如下所示:
Public Sub ShowForm(CallerWorkbook As Workbook)
Const vbext_ct_MSForm As Long = 3
'This is to stop screen flashing while creating form
Application.VBE.MainWindow.Visible = False
'Add to ThisWorkbook, not supplied workbook or VBE will crash - ignore CallerWorkbook
Dim myForm As Object
Set myForm = ThisWorkbook.VBProject.VBComponents.Add(vbext_ct_MSForm)
'Create the User Form
With myForm
.Properties("Caption") = "Select"
.Properties("Width") = 300
.Properties("Height") = 270
End With
'Show the form
Dim finalForm As Object
Set finalForm = VBA.UserForms.Add(myForm.Name)
finalForm.Show
'Remove form
ThisWorkbook.VBProject.VBComponents.Remove myForm
End Sub
效果很好。但是,当我的插件受密码保护时,不允许尝试向其添加临时用户表单。没问题,我只是将临时用户窗体添加到调用代码的工作簿中,因为这不会受到密码保护
Sub ShowForm(CallerWorkbook As Workbook)
Const vbext_ct_MSForm As Long = 3
'This is to stop screen flashing while creating form
Application.VBE.MainWindow.Visible = False
'Add to CallerWorkbook instead
Dim myForm As Object
Set myForm = CallerWorkbook.VBProject.VBComponents.Add(vbext_ct_MSForm)
'Create the User Form
With myForm
.Properties("Caption") = "Select"
.Properties("Width") = 300
.Properties("Height") = 270
End With
'Show the form
Dim finalForm As Object
'Now myForm cannot be found and added
Set finalForm = VBA.UserForms.Add(myForm.Name)
finalForm.Show
'Remove form
CallerWorkbook.VBProject.VBComponents.Remove myForm
End Sub
但是 VBA 似乎无法 看到 其中 myForm.Name
指向现在,因此 Add 方法失败 "Run time error 424: Object required"
有没有办法在另一个工作簿中显示在 运行 时间创建的表单?
您遇到的问题是默认情况下用户窗体是私有实例化的。这意味着一个项目不能引用另一个项目中的用户窗体,如果不能引用该窗体,则不能调用它的 Show
方法。
你的 Set myForm = CallerWorkbook.VBProject.VBComponents.Add(vbext_ct_MSForm)
语句 returns 是 VbComponent
,而不是 UserForm
,所以这就是你不能使用 VBA.UserForms.Add(myForm.Name)
[=32= 的原因]
有两种解决方法:
1 - 在您的加载项中创建一个 PublicNotCreatable
模板用户窗体
用户窗体就像 class,因此它可以设置 Instancing
属性,就像 class 一样。但是,VBE 不会在用户窗体的属性 Window 中公开 Instancing
属性,因此要设置实例化,您需要导出窗体,然后编辑 Attribute VB_Exposed
属性在文本编辑器中的 FRM 文件中,然后再次导入表单。以下是步骤:
- 在您的加载项项目中创建一个名为
TemplateForm
的用户窗体 - 删除
TemplateForm
并在删除之前选择导出表单 - 在文本编辑器中打开
TemplateForm.frm
文件 - 编辑
Attribute VB_Exposed = False
行,使其变为Attribute VB_Exposed = True
- 将更改保存到
TemplateForm.frm
- 将
TemplateForm.frm
导入您的加载项 将 public 函数添加到您的外接程序 returns
TemplateForm
的新实例。我已使此函数接受工作簿引用,以便加载项可以在表单上配置任何特定于工作簿的属性:Public Function GetTemplateForm(CallerWorkbook As Workbook) As TemplateForm Dim frm As TemplateForm Set frm = New TemplateForm 'Set early-bound properties with intellisense frm.Caption = "Select" frm.Width = 300 frm.Height = 270 'Configure CallerWorkbook specific form properties here '... Set GetTemplateForm = frm End Function
然后,您可以在用户的工作簿中显示 TemplateForm 的实例,而无需动态添加表单、处理屏幕闪烁或难以调试的代码:
Sub ShowAddinForm() With MyAddin.GetTemplateForm(ThisWorkbook) 'Do more workbook specific propery setting here... '... .Show End With End Sub
** 注意 - Rubberduck VBA 加载项将很快能够添加 PublicNotCreatable
UserForm。
2 - 让加载项创建用户窗体组件,但让用户的工作簿管理它
这种方法远没有那么优雅。用户需要管理的代码多了很多,屏幕闪烁,代码难以调试。以下是步骤:
将此代码添加到加载项:
Public Function GetTempFormName(CallerWorkbook As Workbook) As String Const vbext_ct_MSForm As Long = 3 'This is to stop screen flashing while creating form Application.VBE.MainWindow.Visible = False 'Add to CallerWorkbook instead With CallerWorkbook.VBProject.VBComponents.Add(vbext_ct_MSForm) .Properties("Caption") = "Select" .Properties("Width") = 300 .Properties("Height") = 270 GetTempFormName = .Name End With End Function Public Sub RemoveTempForm(CallerWorkbook As Workbook, FormName As String) With CallerWorkbook.VBProject.VBComponents Dim comp As Object Set comp = .Item(FormName) .Remove .Item(FormName) End With End Sub
然后,在用户的工作簿中,添加以下代码:
Sub GetAddinToCreateForm() Dim FormName As String FormName = MyAddin.GetTempFormName(ThisWorkbook) With VBA.UserForms.Add(FormName) .Show End With MyAddin.RemoveTempForm ThisWorkbook, FormName End Sub