【问题标题】:ThisWorkbook Workbook_Open fails to show userform if Excel or Word already open如果 Excel 或 Word 已打开,则 ThisWorkbook Workbook_Open 无法显示用户窗体
【发布时间】:2020-11-17 22:09:55
【问题描述】:

我使用 Office365。我有一个名为 Test.xlsm 的 Excel 文件,其中包含一个名为 frmMain 的用户表单。
在 ThisWorkbook 对象中,然后在 Workbook_Open 事件中,我有以下代码:

    Private Sub Workbook_Open()
       Worksheets("Main").Activate
       frmMain.Show
    End Sub

这意味着每次打开 Test.xlsm 文件时都会启动(显示)frmMain 用户窗体。
但是,如果另一个 Excel 或 Word 文件已打开,frmMain 用户表单将无法启动/显示。
有没有办法让 Excel 或 Word 文件已经打开并且仍然能够启动和使用 Test.xlsm 文件及其用户表单 frmMain ?这是 Office365 的问题吗?

更新:

还尝试将应用程序安全性设置为低,以防它默认为 msoAutomationSecurityByUI:

Private Sub Workbook_Open()

dim frm As frmMain
Dim secAutomation As MsoAutomationSecurity

set frm = New frmMain
secAutomation = Application.AutomationSecurity

Application.AutomationSecurity = msoAutomationSecurityLow
Worksheets("Main").Activate
frmMain.Show

End Sub

更新:

还尝试将其放在独立模块上(不在 ThisWorkbook 中):

Private Sub runForm()
   frmMain.Show
End Sub

然后从 ThisWorkbook > Workbook_Open 事件中这样调用它:

Private Sub Workbook_Open()
   Application.OnTime VBA.Now, "name of file '!runForm.runForm"
End Sub

在所有其他 Excel 关闭的情况下,这也会打开 Test.xlsm 和用户表单,但是当 .xlsx 已经打开时,同样的问题 - 打开文件但没有打开用户表单。

【问题讨论】:

  • 这不能回答您的问题,但您确实应该使用表单的实例而不是默认实例。 Like this
  • 您的意思是允许用户手动打开用户表单的实例吗?我需要在打开文件后立即打开表单。
  • 不,我的意思是创建表单的new 实例,而不是使用预先声明的默认实例。我的建议/答案显示了如何做到这一点。
  • 您确定 Application.EnableEvents 没有被已打开的工作簿设置为 False 吗?尝试这个。在打开工作簿之前,在 VBE 的即时窗口中键入 Application.EnableEvents = True。现在检查...
  • 是的,其他工作簿是普通的 .xlsx,在启动 Test.xlsm 之前没有运行其他宏。 EnableEvents 默认值为 True。无论如何,我只是在 Workbook_Open 事件中的 frm.Show 之前添加了 Application.EnableEvents = True 。启动 Test.xlsm 并在后台打开另一个普通的 .xlsx 工作簿(空白工作簿)。 Test.xlsm 已打开,但 frm.Show 未运行且用户窗体未显示。

标签: excel vba office365 userform


【解决方案1】:

也许您可以将您的打开逻辑从ThisWorkbook 对象中移出并使用Auto_Open 方法移入模块中:

Private Sub Workbook_Open()
   Dim frm as frmMain
   Set frm = new frmMain

   Worksheets("Main").Activate
   frm.Show
End Sub

编辑: 因为我不确定为什么 ThisWorkbook.Workbook_Open 事件不起作用,所以我只是为自己尝试了它,它对我来说效果很好......但是让我知道切换到 Auto_Open 是否有效?

【讨论】:

  • 我在 Auto_Open 模块(ThisWorkbook 模块之外)上使用了您的代码,但它不起作用,即什么也没发生。我在 ThisWorkbook Workbook_Open 事件模块中使用它,它“有时”工作!顺便说一句,我正在打开另一个不相关的 Excel 文件进行测试。有时 Test.xlsm 会打开,frmMain 会出现,而其他时候不会!我不知道发生了什么......
  • 您的表单是模态的吗?有没有可能在屏幕外打开或其他什么?
  • 绝对是Modal。但我认为你可能正在做某事。实际上,Test.xlsm 启动并且用户表单未能出现的时间(因为打开了另一个 Excel 文件)Test.xlsm 仍然打开并显示“主”表(只是不是用户表单),是的,它的行为就像它处于 vbModeless 模式,即我可以在“主”表上单击并选择单元格等。但是当 Test.xlsm 正确打开时,即启动用户窗体时,我无法在后面的表上单击等等。即正确模态模式。
  • @Badda_Bing,想知道您是否可以发布(如果您有任何内容)表单的初始化代码?
  • 一开始我还以为那里可能有什么东西,所以我把 UserForm_Initialize 模块注释掉了。不幸的是,它没有任何区别。我还尝试将应用程序安全性设置为低,以防它默认禁用从 Open 事件启动的宏。我正在更新上面的问题以显示代码。
【解决方案2】:

当打开另一个工作簿时,Workbook_Open 事件不会为新打开的工作簿正确触发。这是一个错误。

解决此问题的一种方法是利用自定义 RibbonUI 对象,以便在打开工作簿时触发事件。

设置起来并不简单,但您只需要做一次。需要 3 个步骤:

1) 在 ThisWorkbook 对象中设置 Friend 方法
ThisWorkbook 模块中编写以下代码:

Option Explicit

Private m_openAlreadyRan As Boolean

Friend Sub FireOpenEventIfNeeded(Optional dummyVarToMakeProcHidden As Boolean)
    If Not m_openAlreadyRan Then Workbook_Open
End Sub

Private Sub Workbook_Open()
End Sub

注意几点:
a) 需要虚拟参数来隐藏 框中的方法 (Alt+F8)
b) 该方法被声明为Friend,所以它只能被这个项目访问
c) 需要一个布尔变量 (m_openAlreadyRan)。这将在稍后的第 3 阶段使用

2) 将 CustomRibbon 嵌入到您的工作簿中
首先,我们需要一些代码来调用在步骤 1 中创建的方法。
在您的工作簿中创建一个标准模块并将其命名为 CustomUI。将以下代码添加到 CustomUI 模块:

Option Explicit

Public Sub InitRibbon(ribbon As IRibbonUI)
    ThisWorkbook.FireOpenEventIfNeeded
End Sub

这个方法需要在 Ribbon 初始化的时候调用。也就是说,这个方法是Ribbon使用的回调方法。

这是棘手的部分。这可以通过多种方式完成,您可以在网上找到一些工具。但是,我将向您展示如何手动操作:
a) 关闭并保存您的工作簿

b) 如果您不使用存档程序,请下载存档程序。我使用的是免费的7-Zip

c) 打开存档器并浏览到您的工作簿文件夹

d) 右键单击​​工作簿并选择在内部打开

e) 创建一个名为 customUI 的文件夹。您会注意到 Workbook 文件实际上是文件的存档

f) 打开记事本或任何文本编辑器并使用以下 xml 创建一个新文件:

<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui" onLoad="InitRibbon"></customUI>

请注意,onLoad 回调的名称与 VBA 中创建的方法相匹配,即 InitRibbon

g) 将文本文件(任何地方)保存为 customUI.xml(确保您没有双重扩展名(例如 .xml.txt)

h) 将 .xml 文件拖放到存档器内的 customUI 文件夹中

i) 返回上一级并打开 _rels 文件夹。您应该会看到一个 .rels 文件

j) 编辑 .rels 文件(右键单击然后编辑应该打开记事本)

k) 添加xml:

<Relationship Id="rId10" Type="http://schemas.microsoft.com/office/2006/relationships/ui/extensibility" Target="customUI/customUI.xml"/>

这需要结束 &lt;/Relationships&gt; 标记之前。不是之后。 我使用了 rId10,但您可以查看文件中的所有其他 rId 编号并选择下一个可用的编号。 确保不要重复现有的 rId

l) 将您的编辑保存到文件并退出存档,同时确保您也保存存档编辑(如果您使用带有确定/取消框的 7-Zip,应该会提示您)

m) 关闭存档器。你已经完成了它

3) 设置 Workbook_Open 事件
我们需要考虑在第 1 步创建的布尔值(这样我们就不会两次运行相同的代码)和窗口视图的受保护状态。
将步骤 1 中的代码(在 ThisWorkbook 中)替换为:

Option Explicit

Private m_openAlreadyRan As Boolean
Private m_isOpenDelayed As Boolean

Friend Sub FireOpenEventIfNeeded(Optional dummyVarToMakeProcHidden As Boolean)
    If Not m_openAlreadyRan Then Workbook_Open
End Sub

Private Sub Workbook_Activate()
    If m_isOpenDelayed Then
        m_isOpenDelayed = False
        InitWorkbook
    End If
End Sub

Private Sub Workbook_Open()
    m_openAlreadyRan = True
    Dim objProtectedViewWindow As ProtectedViewWindow
    '
    On Error Resume Next
    Set objProtectedViewWindow = Application.ProtectedViewWindows(Me.Name)
    On Error GoTo 0
    '
    m_isOpenDelayed = Not (objProtectedViewWindow Is Nothing)
    If Not m_isOpenDelayed Then InitWorkbook
End Sub

Private Sub InitWorkbook()
    If VBA.Val(Application.Version) < 12 Then
        MsgBox "This Workbook requires Excel 2007 or later!", vbCritical, "Closing"
        Me.Close False
        Exit Sub
    End If
    '
    With New frmMain
        .Show
        'Other code
        '
        '
        '
    End With
End Sub

请注意以下几点:
a) _Open 事件代码延迟到 _Activate 事件,以防 Window View 受到保护
b) _Open_Activate 都指向 InitWorkbook 方法。您可以在此处添加工作簿打开时需要运行的代码
c) m_openAlreadyRan_Open 事件中设置为 True,以便 FireOpenEventIfNeeded 方法不会不必要地调用 _Open (即当错误没有发生时,因为没有其他书籍打开)
d) 我使用了 frmMainNew 实例,正如 @ArcherBird 提到的那样。通过调用frmMain.Show 来使用表单的全局实例被认为是不好的做法。此外,您可以创建一个变量,而不是 With New frmMain

Dim f As New frmMain
f.Show

【讨论】:

  • 我按照所有步骤操作,您的解决方案 100% 解决了问题。对于未来的用户,请注意,第 2 步中的模块需要命名为 .xlm 上引用的 'customUI' 而不是 'CustomUI' 。非常感谢克里斯蒂安,太好了!
  • @Badda_Bing 很高兴它成功了。标准模块的名称无关紧要。可以是任何东西。无论模块名称如何,都会调用 InitRibbon 方法。但是,文件存档中的文件夹名称和文件名称 /customUI/customUI.xml 必须与 .rels 文件中步骤 2) 子步骤 k) 中添加的 xml 片段匹配。只要它们匹配,它们也可以使用不同的名称。
猜你喜欢
  • 2011-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多