提问人:Greedo 提问时间:7/27/2018 最后编辑:Mathieu GuindonGreedo 更新时间:7/27/2018 访问量:1184
在运行时将用户窗体添加到其他工作簿
Add userform to a different workbook at runtime
问:
我打开了一个插件和一个工作簿。加载项是一个 .xlam 文件,在工作簿中我添加了对它的引用。加载项受密码保护。
可以从我的工作簿中运行插件的公共方法。但是,插件中的一种方法用于打开在运行时创建的用户窗体,如下所示VBA.UserForms.Add
假设包含引用的工作簿具有以下内容: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 似乎看不到指向现在的位置,因此 Add 方法失败,并显示myForm.Name
"Run time error 424: Object required"
有没有办法在另一个工作簿中显示运行时创建的表单?
答:
您遇到的问题是,默认情况下,用户窗体是私有实例化的。这意味着一个项目不能引用另一个项目中的用户窗体,如果不能引用该窗体,则无法调用它的方法。Show
您的语句返回 a ,而不是 ,所以这就是为什么你不能使用Set myForm = CallerWorkbook.VBProject.VBComponents.Add(vbext_ct_MSForm)
VbComponent
UserForm
VBA.UserForms.Add(myForm.Name)
有两种方法可以解决这个问题:
1 - 在外接程序中创建模板用户窗体PublicNotCreatable
用户窗体类似于一个类,因此它可以设置其属性,就像类一样。但是,VBE 不会在用户窗体的“属性”窗口中公开该属性,因此若要设置实例化,需要导出窗体,然后在文本编辑器中编辑 FRM 文件中的属性,然后再再次导入窗体。步骤如下:Instancing
Instancing
Attribute VB_Exposed
- 创建在外接程序项目中命名的用户窗体
TemplateForm
- 删除并选择在删除表单之前导出表单
TemplateForm
- 在文本编辑器中打开文件
TemplateForm.frm
- 编辑该行,以便读取
Attribute VB_Exposed = False
Attribute VB_Exposed = True
- 将更改保存到
TemplateForm.frm
- 导入到加载项中
TemplateForm.frm
添加一个公共函数,该函数将 的新实例返回到外接程序。我已使此函数接受工作簿引用,以便加载项可以在窗体上配置任何特定于工作簿的属性:
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
2 - 让外接程序创建用户窗体组件,但让用户的工作簿管理它
这种方法并不那么优雅。用户需要管理的代码还有很多,并且屏幕闪烁,并且难以调试代码。步骤如下:
将此代码添加到加载项:Add this code to the add-in:
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
评论
UserForm
Show
Set finalForm = myForm.Designer
finalForm
As UserForm