【问题标题】:Userform opening on wrong workbook在错误的工作簿上打开用户表单
【发布时间】:2021-11-26 04:30:28
【问题描述】:

我有一个用户表单,它有一个命令按钮来打开另一个用户表单。这在大多数情况下效果很好,但在特定情况下它根本不起作用。

所述用户窗体的用户通常在多个监视器上工作,并且还打开多个工作簿。这些其他工作簿与我的工作簿没有关联。

如果用户正在监视器 1 上的另一个工作簿中工作,然后单击按钮以在监视器 2 上打开辅助用户窗体,则辅助用户窗体会在监视器 1 上打开,并且其行为就像它的父级是另一个工作簿一样。要纠正此行为,用户需要单击监视器 2 的工作簿上的一个单元格,然后单击该按钮以打开辅助用户窗体。所以这似乎是一个工作簿激活问题,但事实并非如此。

在显示带有代码的辅助用户窗体之前,我尝试了不同的方法来激活正确的工作簿,但无济于事。

这是我在单击按钮时用于启动辅助用户窗体的基本代码:

Private Sub CommandButton1_Click()

    With UserForm2
        .StartUpPosition = 0
        .Left = Application.Left + (0.5 * Application.Width) - (0.5 * .Width)
        .Top = Application.Top + (0.5 * Application.Height) - (0.5 * .Height)
        .Show vbModeless

    End With

End Sub

我发现这种想法我只需要在显示之前显式设置用户窗体父窗口,但用户窗体根本不会使用以下代码打开: http://www.cpearson.com/excel/SetParent.aspx

我希望这是有道理的。这有点难以解释。

【问题讨论】:

  • 表单是无模式的,所以我对“父窗口”的含义感到困惑。这只是定位表单的问题吗?
  • “并且表现得像它的(原文如此)父母是另一个工作簿”到底是什么意思?此外,With 块是血腥的误导,一旦你意识到With New 包含在End With 被销毁的对象引用(即,如果你将代码更改为With New,表单将在显示后立即被销毁) .
  • 不,定位表单不是问题。如果单击任务栏上的“其他工作簿”,辅助用户窗体将获得焦点。我应该在任务栏上单击我的工作簿,并且辅助用户窗体应该得到关注。它是这样的:在监视器2上打开我的用户窗体>在监视器1上打开其他工作簿>单击监视器1工作簿上的单元格>现在单击按钮以在监视器2上打开辅助用户窗体>辅助用户窗体将在监视器1而不是监视器2上打开>单击任务栏上的另一个工作簿将给予辅助用户窗体焦点,指示其父级是另一个用户窗体
  • 请随时 edit 澄清您原来的问题 :)
  • 我目前在家,无法使用双显示器,否则我可能会进行屏幕录制以说明我的意思。我道歉:(

标签: vba excel


【解决方案1】:

如果您有一个对 Workbook 的引用,您希望将其设置为窗体的父级,则只需要将两个窗口句柄传递给 SetParent。对于Workbook,您可以简单地使用您的g_workbook 变量来获取它的Window,它公开了一个Hwnd 属性。

对于UserForm,您需要使用第二个 API 调用 (FindWindow)。只需将窗口的标题传递给它(如果您担心它不是唯一的,则可以选择传递该类)并返回其窗口句柄。把它放在模块顶部的声明中:

#If VBA7 Then
    Private Declare PtrSafe Function SetParent Lib "user32" ( _
        ByVal hWndChild As Long, _
        ByVal hWndNewParent As Long) As Long

    Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" _
        (ByVal lpClassName As String, _
        ByVal lpWindowName As String) As Long
#Else
    Private Declare Function SetParent Lib "user32" ( _
        ByVal hWndChild As Long, _
        ByVal hWndNewParent As Long) As Long

    Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
        (ByVal lpClassName As String, _
        ByVal lpWindowName As String) As Long
#End If

然后,在显示表格之前拨打SetParent

Private Sub CommandButton1_Click()
    With New UserForm2
        .StartUpPosition = 0

        Dim host As Window
        Set host = g_workbook.Windows(1)
        'You can also calculate these on the host position if you want.
        .Left = Application.Left + (0.5 * Application.Width) - (0.5 * .Width)
        .Top = Application.Top + (0.5 * Application.Height) - (0.5 * .Height)

        Dim handle As Long
        handle = FindWindow(vbNullString, .Caption)
        SetParent handle, host.Hwnd

        .Show vbModeless
    End With
End Sub

正如您在问题中推测的那样,这似乎可以解决焦点问题。它是否稳定 是一个不同的问题 - 可以想象,如果您将父级设置为错误的工作簿,则关闭新的父级工作簿可能会导致意外行为。

【讨论】:

  • 谢谢@Comintern 这看起来很有趣。明天我会在我的办公桌前尝试并接受这个答案,如果我能让它工作的话。感谢大家的宝贵时间,如果其他人有任何建议,我们非常欢迎。
  • 这行得通,但有一些奇怪的副作用。辅助用户窗体上的任何组合框都不会填充(填充组合框的代码运行但窗口上没有任何更新)。会多尝试一下这个想法。
【解决方案2】:

另一种选择是确保在激活工作簿之前卸载表单。

从您的命令按钮:

  1. 卸载我的表单
  2. MyWorkbook.Activate
  3. 加载我的表单
  4. MyForm.Show

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-16
    相关资源
    最近更新 更多