我有一个用户窗体,该窗体具有一个用于打开另一个用户窗体的命令按钮。在大多数情况下,此方法效果很好,但在某些特定情况下它根本无法工作。
所述用户表单的用户通常在多个监视器上工作,并且还打开多个工作簿。这些其他工作簿与我的工作簿无关。
如果用户正在监视器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
我希望这是有道理的。很难解释。
答案 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
正如您在问题中所推测的那样,这似乎可以解决焦点问题。它是否稳定是一个不同的问题-可以想象,如果将父级设置为错误的工作簿,则关闭新的父级工作簿可能会导致意外的行为。