防止模态窗体在退出时关闭所有未关闭的非模态窗体

3
我在Excel中使用VBA窗体时遇到了一些奇怪的行为。我有一个调用其他窗体的模式窗体,作为一个集线器。其他窗体是以模态方式调用的。问题是,只要子窗体隐藏或卸载,父模态窗体也会关闭。
我试图找到答案,但即使有类似的问题存在,也没有一个提供有效答案的问题。
经过一番测试,我确定任意数量的打开模式窗体都会以同样的方式关闭。此外,我无法在新工作簿的最小模型中重现这个问题。之后,我开始逐步添加原始工作簿的所有组件(有几个模块、10-20个类和几个窗体),以查看问题何时出现。
当我发现即使我将所有东西都导入回来,问题仍然没有重新出现时,我既宽慰又烦恼。我的结论是这是某种偶然事件,不会再困扰我。但是,不久之后,当我添加了另一个具有相同调用代码的子窗体时,同样的问题又出现了,但旧的窗体没有出现这个问题。
然后我导出了出现问题的窗体,从工作簿中删除它,然后再次导入它。嗯,它又可以工作了。
有没有遇到过这种行为的人?我做错了什么吗?或者我应该把这个当作一个恼人但可避免的错误吗?
请在下面找到问题的最小模型,不包括所有内容:
调用主窗体的模块:
Sub testA()

 Dim main1 As MainForm1

 Set main1 = New MainForm1

 main1.Show (vbModeless)

End Sub

主表单:

Option Explicit

Dim formobject As frmPickInjection

Private Sub CommandButton1_Click()

 Set formobject = New frmPickInjection


 With formobject
     .Show (vbModal)
     Label1.Caption = CStr(.SelectedInjection)
 End With

End Sub

子表单:

Option Explicit

Public passvar As Boolean

Private Sub CheckBox1_Click()
 passvar = CheckBox1.Value
End Sub

操作系统:Microsoft Windows 7企业版 6.1.7601(服务包1版本号7601)

Excel 版本:Office365 Excel 2016(16.0.6729.1014),64 位

VBA 版本:7.1

3个回答

4

我之前遇到过这个问题。不确定是否已经解决,但对于未来想要解决此问题的用户,唯一的方法是以模态显示用户窗体,然后以非模态方式隐藏和重新显示用户窗体,从而解决这个麻烦且间歇性的问题。

Unload MyChildUserform
MyParentUserform.Show vbModal
MyParentUserform.Hide
MyParentUserform.Show vbModeless

虽然有些笨重和烦人,但它似乎能够正常工作并保持一致性。

编辑:

在我看来,更好的解决方案是自己控制表单的形式。

声明:

Public Declare Function EnableWindow lib "user32.dll" (ByVal hWnd as Long, ByVal fEnable as Long) as Long
Public Declare Function FindWindow lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName as String, ByVal lpWindowName as String) as Long

Public Enum MakeAsModal
    Modal = 0
    Modeless = 1
End Enum

Public ghWndParent as Long

公共子程序(s):
Public Sub ChangeModality(ByRef hWnd as Long, ByVal isModal as MakeAsModal)
    On Error Resume Next
    Dim RetVal as Long
    RetVal = EnableWindow(hWnd,isModal)
End Sub

父表单:

Private Sub Userform_Initialize()
'Parent Form
    ghWndParent = FindWindow(vbNullString, Me.Caption)
End Sub

Private Sub CallChild()
'Parent Form
    ChildUserform.Show vbModeless
    ChangeModality ghWndParent, Modal
End Sub

子表单:

Private Sub Userform_QueryClose(Cancel As Integer, CloseMode as Integer)
'Child Form
    ChangeModality ghWndParent, Modeless
End Sub

太棒了!我没能解决它,但是我对解决方法感到满意:导出所有表单-再次导入所有表单,并将其分配给一个宏。这个命令序列只需要执行一次,然后就可以暂时修复它,还是必须成为表单调用代码的一部分?出于好奇 - 你是如何找出这个解决方法的? - Juraj Ahel
我实际上对它进行了进一步的尝试,并找到了一个更好的解决方案...尽管它涉及WinAPI命令。将用新的解决方案纠正上面的答案。 - Gnixxus

0
今天我遇到了这个问题,但我找到了一个解决方法,可以防止非模态窗体在模态窗体关闭事件中关闭。
简单地说,将UserForm属性“ShowModal”设置为True即可。 UserForm ShowModal Property to True 然后,在显示窗体时,只需使用UserForm.Show(即不指定vbModal或vbModeless)。在我的解决方法中,我将此.Show调用包含在相应模态UserForm的UserForm_Initialize事件中。现在,当您关闭此模态窗体时,它不会将每个父非模态窗体一起关闭。
对我来说,这个问题很重要,因为我的模态Userform必须是模态的,因为它包含一个RefEdit控件。经过进一步的调查和故障排除,我无法确定是什么导致了这个模态窗体的问题。我希望有更好的VBA知识的人来看看,但我担心他们可能已经转向更绿色的草地了...

0

我知道这是一个非常老的帖子,但我在寻找答案时发现了它,所以我想分享我的解决方案,希望能帮助其他人。

我发现的另一个选项是不将模态表单创建为新表单;相反,如果您只是将表单显示为模态而不初始化新表单,则它将正确隐藏而不隐藏父表单。当然,如果您需要同时拥有此特定表单的多个实例,则此方法无效,但对于我的目的(它会弹出一个搜索用户表单以选择传回父表单的值),之后隐藏对我有效。


有趣。已经有一段时间没有积极使用VBA了 - 你的意思是说表单根本不需要初始化,只需显示类本身(例如从我的代码frmPickInjection.Show())?也就是说,有一个默认实例,只要你不需要多个实例,你可以将其用作单例?如果这确实可以可靠地工作,那么这是一个不错的解决方法,但我仍然更喜欢Gnixxus的方法,它似乎更通用,而且也不会非常复杂。 - Juraj Ahel
1
只要你所指的“类”是指用户窗体而不是实际的类,那么所有方面都是正确的。 - Michael Katzaroff
我的使用案例是一个搜索框,我可以重复使用它来填充不同表单上的多个文本框。在文本框的AfterUpdate事件中,我使用搜索值/参数更新公共变量(SearchText作为字符串,SearchType作为字符串),以执行哪个搜索,然后将表单显示为模态。该表单使用公共变量执行SQL命令,并将记录列表返回到列表框。 - Michael Katzaroff
我将列表框中选择的值用作另一个公共变量,原始用户窗体将读取并在我双击列表框中的值或单击选择按钮时将结果写入TB。然后搜索用户窗体将隐藏而不关闭“父”窗体(我猜它实际上不是父窗体,因为它没有初始化搜索窗体的新实例)。对于多个帖子感到抱歉,在编写整个内容后才意识到有字符限制。 - Michael Katzaroff
谢谢您的澄清。我认为是这样,但是同一工作簿之间的实例是否是分开的呢?也就是说,如果您将工作簿复制到不同的名称下并同时打开它,并使用此方法,那么相同名称的表单不会发生冲突,因为它们位于不同的VBA项目中,因此是不同的表单? - Juraj Ahel
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接