在错误的工作簿上打开用户表单

时间:2018-10-03 00:15:34

标签: excel vba excel-vba

我有一个用户窗体,该窗体具有一个用于打开另一个用户窗体的命令按钮。在大多数情况下,此方法效果很好,但在某些特定情况下它根本无法工作。

所述用户表单的用户通常在多个监视器上工作,并且还打开多个工作簿。这些其他工作簿与我的工作簿无关。

如果用户正在监视器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

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

1 个答案:

答案 0 :(得分: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

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