【问题标题】:Activate a Workbook Invisibly from a UserForm从用户窗体不可见地激活工作簿
【发布时间】:2020-08-17 16:36:14
【问题描述】:

我已经研究这个问题两个多星期了,包括在这里提出一个问题,但我的问题和解决方案都错了。所以我想再试一次。

我有一个在 Excel 中打开的用户表单。它列出了所有当前打开的工作簿,并允许我打开其他工作簿。我的程序将在任何工作簿中添加、修改或删除表。表格必须在程序生成的名称的工作表中。如果它们不存在,将添加此类工作表。添加工作表后,它会根据其名称排序到选项卡序列中的特定位置。这些操作中的每一个都适用于 ThisWorkbook。我很难确定它们中的一些在哪些条件下不能在其他工作簿上工作,因此无法找到治疗方法。

从表格开始。它是从 ThisWorkbook 中的工作表调用的。我有它的模态。现在它是无模式的。我没有观察到任何差异。但是,由于存在大量可能性,我很难为全面测试创建一个好方法。我正在寻找可以节省大量试错时间的知识。

使用此代码添加工作簿。顺便说一句,据我所知,在此过程中暂停 ScreenUpdating 是无效的。将窗口设置为不可见会导致效果。

Dim Fltr As String
Dim Ffn As Variant
Dim Fn() As String
Dim Wb As Workbook
Dim i As Long

Fltr = "Excel Workbooks|*.xls*||All Excel files|*.xl*"
Ffn = FileOpenName("Select a Target Document", Fltr, , True)
If Not IsEmpty(Ffn) Then
    Application.ScreenUpdating = False
    For i = 1 To UBound(Ffn)
        Fn = Split(Ffn(i), "\")
        On Error Resume Next
        Set Wb = Workbooks(Fn(UBound(Fn)))
        If Err Then
            Set Wb = Workbooks.Open(Ffn(i))
            ActiveWindow.Visible = False
        End If
    Next i
    ThisWorkbook.Activate
    Application.ScreenUpdating = True

加载表单时,ThisWorkbook 处于活动状态。所有其他打开的工作簿都是不可见的。上述代码的效果是新的工作簿也是不可见的,并且 ThisWorkbook 保持活动状态。表面上没有区别,但似乎只是表面上的。

当我想将工作表添加到另一个工作簿时,该工作簿显然必须处于活动状态。我已经成功地使用模态和非模态表单完成了此操作,但现在我的代码拒绝激活工作簿(Wb.Activate 被忽略,没有通知)并且工作表被添加到 ThisWorkbook。这是添加工作表的代码。

Private Function CreateLibrary(Wb As Workbook, _
                               Frm As Modifier) As Worksheet
    ' SSY 052 ++ 26 Apr 2020

    Dim ClmWidth As Variant                     ' default column widths
    Dim C As Long

'    Windows(Wb.Name).Visible = True
    With Wb.Worksheets.Add
        With .Cells
            .HorizontalAlignment = xlLeft
            .VerticalAlignment = xlTop
            .WrapText = True

            ' Library font = Arial / Table font = Calibri
            With .Font
                .Name = "Arial"
                .Size = 10
            End With
        End With

        ' set default widths
        ClmWidth = Array(8.43, 10.57, 52, 24, 24)
        For C = 0 To UBound(ClmWidth)
            .Columns(C + 1).ColumnWidth = ClmWidth(C)
        Next C

        .Rows.RowHeight = 12.75
        .Name = Frm.TbxLib.Value
    End With

    Set CreateLibrary = ActiveSheet
End Function

我认为原因是我无法在不可见的窗口中激活工作簿。我相信它之前工作的原因是因为窗口是不可见的,尽管它的 Visible 属性设置为 True。我认为它是在我没有打开的工作簿上,但是在调用表单时打开的工作簿。这些工作簿不在隐形窗口中。只是,窗户没有活动。其中一个问题是 Excel 将激活打开新工作簿的窗口。因此我上面的代码应该是错误的。我在 SO 上找到了方法。

在我之前关于此主题的问题中,我抱怨新工作表被添加到错误的位置,有时是 ThisWorkbook 而不是指定的位置。我认为通过更新屏幕可以解决问题。那不是真的。根据打开预期工作簿的方式,新工作表将位于错误的工作簿中。我的代码只是将它添加到 ActiveWorkbook。但我还是不知道为什么它总是排在倒数第二位。我发现我的代码在所有其他代码之前插入了工作表(具有该效果的代码),但此后立即运行了一个排序器,这可能会再次移动工作表,这取决于工作簿中已经存在哪些其他工作表,并且可能将其移动到ActiveWorkbook 也是如此。我怀疑排序器可能会根据工作簿是否处于活动状态以及它的窗口是否可见或隐藏而产生问题。分拣机在正常情况下工作正常,但这样做的效果是我不知道工作表是否插入到正确的位置开始。现在我在没有分拣机的情况下进行测试,但在插入工作表时遇到了问题。

我陷入了一个恶性循环,找不到出路。我认为,表格本身是我问题的核心。默认情况下,Excel 的 VBA (2013) 将激活表单的工作簿。不再可能拥有无模式表单并翻阅在该表单上选择的工作簿。但这也不是我想要的。我希望所有工作簿(可接受的 ThisWorkbook 除外)都留在后台。我认为如果我能找到一种方法来打开其他工作簿并强制它们进入与打开表单时已经打开的工作簿相同的技术位置——在可见但非活动的窗口中,我的难题将变得可以解决。我阅读了某人的建议,暂时关闭表单并重新加载,但这似乎是拿锤子打苍蝇。

编辑:- 同时,我在上面的过程中添加了以下代码。

    ThisWorkbook.Activate
    Dim Win As Window
    For Each Win In Application.Windows
        Debug.Print Win.Index, Win.Caption,
        Debug.Print Win Is ActiveWindow,
        Debug.Print Win.Visible
    Next Win
    Application.ScreenUpdating = True

它产生了以下惊人的结果。

  • Windows(1) 是 ThisWorkbook
  • 加载表单时打开了 Windows(2)
  • 其他 3 个是使用上面的代码添加的,我将 ActiveWindow.Visible = False 更改为 Windows(1).Visible = False Windoes(1) 应该是 ActiveWindow,而不是 (2)。实际上,Windows(1) 和 (3) 在 Excel 应用程序底部的选项卡行中可见,但其他 3 个不可见,包括之前可见的 #2。观察这些窗口没有 Visible 属性集。当我关闭表单时,所有这些都发生了变化。我运行了相同的代码并得到了这个打印输出,这也没有意义。但是,现在所有 5 个窗口都包含在 Excel 窗口底部的选项卡栏中,显然与它们的可见性状态无关。

我还想知道在我的上下文中无模式形式的意义何在。它似乎被设计为允许切换自己的工作簿的工作表。因此,没有区别是最好的情况。最糟糕的是什么?

【问题讨论】:

  • 快速说明...and the sheet gets added to ThisWorkbook. 只有在您不完全符合Sheets.Add 的条件时才会发生这种情况。如果您完全符合前 wbThat.Sheets.Add... 的条件,则工作表将添加到正确的工作簿中。
  • @Siddarth Rout 感谢您花时间研究我的问题。这里存在一些限制,这些限制植根于工作簿的可见性、它们的活动或非活动状态以及用户窗体施加的限制。
  • 起初我指定了工作簿,但没有插入工作表。然后我尝试激活目标工作簿并指定 ActiveWorkbook。这导致工作表被插入到 ThisWorkbook 中。我目前的研究旨在找出如何激活除用户表单 (ThisWorkbook) 之外的工作簿。您对采用哪种方法的建议会有所帮助,并建议在我的计划中我应该在哪里引入价值不菲的变革。
  • 我想帮助你,但你的第一条评论(现在已删除)让我气馁:) 无论如何。我希望看到您的工作表添加代码,如果可能的话(?)包含代码和用户表单的工作簿。如果您选择共享工作簿,请记住从中删除任何机密数据。
  • @Siddarthy Rout。谢谢你原谅我的失礼。我将非常重视您的持续支持。但是,我不愿意接受像我这样的项目。它太复杂了,意味着耗时。请询问您想知道的任何细节,并相信我的答案以及我的测试。如果你告诉我怎么做,我们可以把它移到聊天中。添加工作表的代码不显眼且正确。但是,如果目标工作簿不是 ThisWorkbook,则可能不会添加工作表,因为工作簿不是用户表单定义为活动的工作簿,或者因为目标不可见。

标签: excel vba


【解决方案1】:

无论我的问题是否有解决方案,很明显我现在找不到它。因此,我做了以下决定。

  1. 当用户单击“确定”按钮时,我将关闭并卸载用户表单。我希望这将消除可见窗口和不可见窗口之间存在的任何差异,并允许我激活我想要的任何一个。
  2. 我将激活用户在表单中选择的工作簿并使其窗口处于活动状态且可见,希望在用户表单关闭和卸载后不再干扰该过程。
  3. 我将停止使用无模式用户表单。它的方式似乎对我访问工作簿的能力没有影响。它的外观和气味都像一条红鲱鱼。

======== 编辑 2020 年 5 月 18 日 我已经实施了上述步骤并使项目按预期工作。我对这个问题的最终判断是,它是由存在阻止激活其他工作簿的开放用户表单引起的。所有其他问题都是由此产生的副作用。

【讨论】:

    【解决方案2】:

    对于它的价值,我可能会进行以下更改:

    而不是With Wb.Worksheets.Add 我会这样做: wb.sheets.add.name = "bob" 要么 wb.sheets.add (before:=wb.sheets(1)).name = "bob" 或将 sheet(1) 替换为 sheet("neil")

    那么你可以做with wb.sheets("bob") - 远离 activeworkbook 和 activesheet。

    我很确定 if Err then 不起作用 - Err 是一个对象而不是布尔变量。所以也许它应该是If Err.Number <> 0 then,你需要在循环之前和之后任何时候包含Err.Clear,否则你将进入循环的每次重复的If语句

    【讨论】:

    • 感谢您的关注。在一行中为新工作表分配名称很简洁。事实上,Err 对象的默认属性是 .Number。 If [any number <>0] 评估为 True。因此,严格来说,<> 0 不是必需的。 On Error Resume Next 重置 Err 对象,与 Err.Clear 相同。因此,在循环中,它取代了后者。
    猜你喜欢
    • 2019-11-19
    • 2015-01-18
    • 2014-07-02
    • 2019-03-03
    • 1970-01-01
    • 2023-04-05
    • 2017-01-16
    • 1970-01-01
    • 2020-08-06
    相关资源
    最近更新 更多