我有一个插件和一个工作簿。该插件是一个.xlam文件,并且在工作簿中添加了对该文件的引用。该插件受密码保护。
可以从我的工作簿中运行插件的公共方法。但是,插件中的一种方法利用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"
是否可以在其他工作簿中显示在运行时创建的表单?
答案 0 :(得分:6)
您遇到的问题是,默认情况下UserForms是私有实例的。这意味着一个项目不能引用另一个项目中的UserForm,并且如果不能引用该窗体,则不能调用它的Show
方法。
您的Set myForm = CallerWorkbook.VBProject.VBComponents.Add(vbext_ct_MSForm)
语句返回VbComponent
,而不是UserForm
,因此这就是为什么您不能再使用VBA.UserForms.Add(myForm.Name)
有两种解决方法:
PublicNotCreatable
模板用户窗体 UserForm就像一个类,因此可以像设置类一样设置其Instancing
属性。但是,VBE不会在UserForms的“属性”窗口中显示Instancing
属性,因此要设置实例化,您需要导出表单,然后在FRM文件中编辑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
用户表单。
这种方法几乎不那么优雅。用户需要管理更多代码,屏幕闪烁,难以调试代码。步骤如下:
将此代码添加到加载项:
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