【问题标题】:How to open a userform through a custom excel ribbon如何通过自定义 Excel 功能区打开用户窗体
【发布时间】:2019-09-06 23:27:38
【问题描述】:

我正在尝试通过自定义 Excel 功能区打开用户窗体。当我单击功能区中的按钮时,它开始初始化并在 workbooks.open 函数上将代码发送到 queryclose 子。显示用户表单代码如下:

Sub RemoveFixture_onAction(control As IRibbonControl)
    SelectedCompType = Fixture
    Set EditComp = New ufUpdateComp
        With EditComp
            .Top = Application.Top + 125
            .Left = Application.Left + 25
            .Show
        End With
End Sub

当代码开始 userform_Initialize 代码时,它最终移动到 query_close 子。代码如下:

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
    'If wb Is Nothing Then UserForm_Initialize
    wb.Close False
End Sub

如上所示,在注释掉的部分中,当代码移至 queryclose 函数时,我尝试返回到初始化子程序。当它运行 workbooks.open 代码时,它移动到 queryclose 子,它说 wb 什么都不是。我尝试单独打开工作簿,然后将工作簿设置为 ActiveWorkbook。我也试过: wb什么都不是 设置 wb = ActiveWorkbook 环形 这个循环无休止地运行,直到我不得不手动取消它。 原来是设置 wb = workbooks.open(Test)

Private Sub UserForm_Initialize()
    Workbooks.Open Test, , , , , DynoCompPassword, True
    Set wb = ActiveWorkbook
    Set ws = wb.Worksheets("Info")
    Set ws = wb.Worksheets("Info")
    Set wsC = wb.Worksheets("Calipers")
    Set wsF = wb.Worksheets("Fixtures")
    Set wsW = wb.Worksheets("Wheel Sims")
    ws.Visible = True
    wsC.Visible = True
    wsF.Visible = True

btnCreate.Enabled = False
Dim rng As Range

lblLocation.Visible = False
tbLocation.Visible = False
Me.cbOut.AddItem "Sent To"
Me.cbOut.AddItem "Scrapped"
Me.cbOut.AddItem "Returned"
Me.btnCreate.Enabled = True

For Each rngprojectcode In ws.Range("ProjectCode")
    Me.cbProjectCode.AddItem rngprojectcode.Value
Next rngprojectcode

Set ProjCodeDictionary = New Dictionary 'Create the dictionary
Dim i As Integer
Dim j As Integer
Dim ProjCodeString As String
Dim AssociatedCodes As ProjectCodeList

If ws Is Nothing Then Exit Sub

    ProjCodeDictionary.CompareMode = vbTextCompare 'Make the .exists method case insensitive in an attempt to avoid duplicate values

    Set AssociatedCodes = New ProjectCodeList 'create the class module which will split up the associated codes into individual values
    i = 1
    While ws.Range("F1").Offset(i, 0) <> ""
        With AssociatedCodes
            .SetCodes = CStr(ws.Range("F1").Offset(i, 0).Value)
            For j = 1 To .NumCodes
                ProjCodeDictionary.Add .ProjCode(j), i 'key, item
            Next j
        End With
        i = i + 1
     Wend

If SelectedCompType = Fixture Then
    Me.lblCompNum.Caption = "Fixture ID"
    Me.btnCreate.Caption = "Update Fixture"
        'Automation Error occurs here
    Me.Caption = "Edit Fixture"
    Me.frChangeFrame.Height = 65
    Me.frChangeFrame.Caption = "Bolt Circle"
    Me.cbPartNum.Text = "FIX"
        For Each rng In wsF.Range("FixtureNum")
        Me.cbPartNum.AddItem rng.Value
        Next rng
    Set tbNumStuds = frChangeFrame.Controls.Add("Forms.TextBox.1", , "True")

为了澄清,只有在用户窗体中按下带有 X 的红色框时,才应激活 queryclose 子。它是用户窗体的内置函数。

【问题讨论】:

  • 所以,只需检查:您有工作簿一,带有打开用户窗体的功能区命令。 Userform_Initialize 打开工作簿二。对吗?
  • 您在问如何从自定义功能区打开用户窗体或如何设置他的活动工作簿?关于打开用户表单,您需要引用打开用户表单的代码(例如,application.run "module1.callUF"),因为这是经过验证的(您可能需要一些错误处理来验证是否打开了相应的工作簿)。你可以set wb = activeworkbook,因为这会覆盖最后的声明,没有问题。
  • 将该代码放入表单的Initialize 处理程序将使处理程序运行在显示表单之前。也就是说,如果您想让该表单在用户单击您的自定义功能区命令时出现,您将需要与该功能区命令关联的代码,该代码针对表单实例调用 Show 方法。
  • 我已经多次阅读这篇文章,但仍然无法弄清楚问题是什么以及显示的代码块与“通过自定义 excel 功能区打开用户窗体”在任何方式,也不是为什么需要涉及表单,或者“它将代码发送到 queryclose 子”是否是一个问题,或者它是否是预期的。请edit澄清。
  • Matthieu,我刚刚在帖子中添加了一些附加信息。问题是当我打开用户表单时,它会在初始化代码期间将我发送到 queryclose 子。 queryclose 子程序唯一应该运行的时间是在用户窗体上按下 X 按钮时。请询问任何有助于诊断此问题的更多信息和代码。

标签: excel vba userform


【解决方案1】:

queryclose 子程序唯一应该运行的时间是在用户窗体上按下 X 按钮时。

但这不是QueryClose 的工作方式。每当表单即将关闭时,UserForm.QueryClose 事件就会被触发,它的参数为您提供取消它的方法,具体取决于促使它关闭的原因。

CloseMode 参数值为vbFormControlMenu(X 按钮 - 参见QueryClose constants)时,您想要有条件地运行wb.Close False

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
    If CloseMode = vbFormControlMenu Then
        wb.Close False
    End If
End Sub

我尝试返回初始化子时代码[...]

不要这样做。事件处理程序旨在由 VBA 本身调用,而不是由用户代码调用。如果您需要调用已在事件处理程序中实现的逻辑,请将代码从处理程序中重构到它自己的过程中:

Private Sub UserForm_Initialize()
    DoInitializationStuff
End Sub

Private Sub DoInitializationStuff()
    '...
End Sub

最后,UserForm.Initialize 事件在表单显示之前被触发。

Set EditComp = New ufUpdateComp ' <~ initialize handler runs before this instruction returns
With EditComp
    .Top = Application.Top + 125
    .Left = Application.Left + 25
    .Show
End With

请注意,如果您只在 With 块中使用局部变量,则无需声明局部变量 - 让该块保留对象引用:

With New ufUpdateComp ' <~ initialize handler runs before this instruction returns
    .Top = Application.Top + 125
    .Left = Application.Left + 25
    .Show
End With

如果您希望DoInitializationStuff 在显示表单之后运行,请在Activate 事件中调用它。

【讨论】:

  • 我更改了 with 语句以打开用户窗体以及查询关闭以涉及关闭模式验证。在我得到一个自动化错误之前它似乎有所帮助:被调用者(服务器 [不是服务器应用程序])不可用并消失了;所有连接都无效。调用可能已执行。有趣的是,如果我调试并单步调试它会起作用,但如果我关闭 excel 并重新打开它,我会得到同样的错误。
  • @LearningVBA 我真的不建议将这种代码放在Initialize 处理程序中。是什么引发了自动化错误,在哪里?表格关闭之前还是之后? “如果我一步一步通过它有效”通常是隐含 ActiveSheet 和/或 ActiveWorkbook 引用的标志,看看 Rubberduck 检查是否可以找到任何引用。
  • Mathieu,我更新了提示中的初始化代码,靠近底部是它抛出自动化错误的地方,我现在要尝试放在一个单独的模块中。
  • @LearningVBA Initialize 处理程序旨在在显示表单之前设置默认控件属性,而不是打开工作簿并对其运行 50 行自动化逻辑。确保将该代码移至另一个模块,但更重要的是不要从UserForm_Initialize 调用它。不过,这已经远远超出了最初的问题。
  • 将我的初始化移动到“DoInitializationStuff”子并在初始化子中调用该子后,它仍然在同一位置出现自动化错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-02
  • 1970-01-01
  • 2013-01-12
  • 2018-11-11
相关资源
最近更新 更多