在运行时将userform添加到其他工作簿

Gre*_*edo 7 excel vba excel-vba vbe

我有一个插件和一个工作簿打开.插件是.xlam文件,在工作簿中我添加了对它的引用.插件受密码保护.

可以从我的工作簿中运行addin的公共方法.然而,在一个插件的方法使用的VBA.UserForms.Add打开是在运行时创建的窗体像这样

让我们说一个引用的工作簿myAddin有这个:

Private Sub callAddin()
    myAddin.ShowForm ThisWorkbook
End Sub
Run Code Online (Sandbox Code Playgroud)

通常,我的插件中的代码如下所示:

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
Run Code Online (Sandbox Code Playgroud)

哪个工作正常.但是,当我的插件受密码保护时,不允许尝试向其添加临时用户表单.没问题,我只是将临时用户表单添加到调用代码的工作簿中,因为这不受密码保护

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
Run Code Online (Sandbox Code Playgroud)

然而VBA似乎无法看到哪里myForm.Name点到现在,所以Add方法失败"Run time error 424: Object required"

有没有办法在另一个工作簿中显示在运行时创建的表单?

Thu*_*ame 6

您遇到的问题是默认情况下UserForms是私有实例.这意味着项目不能引用另一个项目中的UserForm,如果您不能引用该表单,则无法调用它的Show方法.

你的Set myForm = CallerWorkbook.VBProject.VBComponents.Add(vbext_ct_MSForm)陈述返回a VbComponent而不是a UserForm,这就是你不能再使用的原因VBA.UserForms.Add(myForm.Name)

有两种方法:

1 - PublicNotCreatable在加载项中创建模板UserForm

UserForm就像一个类,所以它可以Instancing设置其属性,就像一个类.但是,VBE不会Instancing在UserForms的"属性"窗口中公开该属性,因此要设置实例化,您需要导出表单,然后Attribute VB_Exposed在文本编辑器中编辑FRM文件中的属性,然后再次导入表单.以下是步骤:

  • 创建TemplateForm在加载项项目中命名的UserForm
  • 删除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
    
    Run Code Online (Sandbox Code Playgroud)
  • 在用户的工作簿中,您可以显示TemplateForm的实例,而无需动态添加表单,或处理屏幕闪烁或难以调试的代码:

    Sub ShowAddinForm()
        With MyAddin.GetTemplateForm(ThisWorkbook)
            'Do more workbook specific propery setting here...
            '...
            .Show
        End With
    End Sub
    
    Run Code Online (Sandbox Code Playgroud)

**注意 - Rubberduck VBA加载项很快就可以添加PublicNotCreatableUserForm.

2 - 让加载项创建UserForm组件,但让用户的工作簿管理它

这种方法并不那么优雅.用户需要管理更多代码,屏幕闪烁,代码调试困难.以下是步骤:

  • 将此代码添加到加载项:

    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
    
    Run Code Online (Sandbox Code Playgroud)
  • 然后,在用户的工作簿中,添加以下代码:

    Sub GetAddinToCreateForm()
        Dim FormName As String
        FormName = MyAddin.GetTempFormName(ThisWorkbook)
        With VBA.UserForms.Add(FormName)
            .Show
        End With
        MyAddin.RemoveTempForm ThisWorkbook, FormName
    End Sub
    
    Run Code Online (Sandbox Code Playgroud)