转发注解:
·这里讨论的所有代码和UserForm都在Excel Addin中
· Office是64位系统上的365
我的目标是将无模式UserForm的“父”移动到UserForm处于活动状态时激活的任何工作簿(具有给定的名称类型)。我成功地做到了这一点,当一个工作簿被激活时,使用以下方法重新加载UserForm:
''' Code in an EventClassModule:
Private Sub ExcelApp_WorkbookActivate(ByVal wbActivated As Workbook)
'… Conditional and Supporting Code …
Unload UD_SearchImageNotes
UD_SearchImageNotes.Show vbModeless
虽然这样做是可行的,但这意味着必须保存表单字段,并在.Show之后重新填充这些字段(这看起来效率低下且笨拙)
在寻找可能更好(更简单)的解决方案时,我在这里遇到了类似的问题和解决方案:58658670
我已经实现了建议的解决方案(有微小的变化):
''' Code (in an EventClassModule):
Private Sub ExcelApp_WindowActivate(ByVal wbBook As Workbook, ByVal wnWindow As Window)
Dim lpHWnd As LongPtr, lpHWndActivated As LongPtr
lpHWndActivated = wnWindow.hwnd
lpHWnd = FindWindowA(vbNullString, "Search Image Notes")
If lpHWnd > 0 And wbBook.Name Like "*Image Data*" Then
If GetParent(lpHWnd) <> lpHWndActivated Then
SetParent lpHWnd, lpHWndActivated
End If
End If
procFinish: Set wbBook = Nothing: Set wnWindow = Nothing
End Sub
''' Supporting Code (in a standard module):
Public Declare PtrSafe Function SetParent Lib "user32" (ByVal hWndChild As LongPtr, ByVal hWndParent As LongPtr) As LongPtr
Public Declare PtrSafe Function GetParent Lib "user32" (ByVal hWndChild As LongPtr) As LongPtr
Public Declare PtrSafe Function FindWindowA Lib "user32" (ByVal stClassName$, ByVal stWindowName$) As LongPtr
但是(不幸的是)上面的方法不起作用。事件处理程序的工作方式与FindWindowA相同,但不是为UserForm分配新的父级,而是关闭UserForm。
我在58658670上读到了开场海报上关于解决方案的评论:
"… as soon as I open another workbook from my code, it closes my Userform" and
"… managed to get it working by creating my new workbook first and then opening the workbook"
听起来他们也看到了我看到的症状,但找到了解决办法。可悲的是,我看不出他们的解决方案如何适用于我的情况(因为我没有创建任何工作簿,只是在现有的书籍之间切换)。
有没有人有任何线索,什么可能导致这一点和/或我可能会尝试?
1条答案
按热度按时间dpiehjr41#
是的,即使10年了,SDI仍然令XLAM开发人员感到沮丧。我也看到了“消失”的用户表单,并做了一些修改,使之工作。我注意到的一件事是,当我在任务栏中的Excel缩略图上悬停时,用户表单会出现在我的第二个显示器的边缘,所以我知道它已经加载,但只是不可见。SetParent的使用在某种程度上工作得很好,问题似乎是关于用户表单定位的。当用户表单有了一个新的父级时,它就不再是真正的无模式的了(如果你将它滑向工作簿的边缘,你会看到它位于窗口中,而不是在窗口上方)。父母的改变也会打乱坐标系,但不是以一种有意义的方式。我希望事情是相对于活动窗口的,但事实并非如此。设置userform.left似乎基本上被忽略了,它报告了一些奇怪的数字(这些数字在这个例子中显示在状态栏中,当你离开主显示器时,你会看到它们超过了你的总水平分辨率)。
这并不完美:positionUserForm在我的主显示器上可靠地工作,尽管即使在主显示器上,位置也不像预期的那样一致。当我将一个工作簿移出主显示器时,由于xCoordinate超出了可见空间,当切换到时,窗体停止显示。我希望进一步的API与设备上下文的争论将需要完全正确。
除了状态栏更新之外,我还在一个标准模块中添加了两个变量(hwndUserForm和objUserForm),用于传递用户表单,这样我就不会在类中使用硬编码字符串,并且我让类进行表单定位,这样您就可以从表单切换窗口,或者只需单击另一个打开的窗口即可。希望这能送你回家。