Python 当ProgressDialog和Dialog按顺序打开时,Dialog不是模态的

Python 当ProgressDialog和Dialog按顺序打开时,Dialog不是模态的,python,wxpython,Python,Wxpython,我在Windows7机器上运行带有Python3.6.5的wxPython 4.0.1 msw(phoenix),以及带有Python2.7的wxPython 2.9.4 我观察到一个模态对话框存在问题,它不会阻止对其后面父窗口的访问。只有在运行进度对话框后再运行模式对话框时,才会发生这种情况。这种行为在某种程度上与自定义对话框有关。像wx.MessageDialog这样的集成对话框似乎没有这个问题 为了解决这个问题,我写了一个例子。前两个按钮打开“进度”或“模式”对话框并正常工作。第三个按钮按

我在Windows7机器上运行带有Python3.6.5的wxPython 4.0.1 msw(phoenix),以及带有Python2.7的wxPython 2.9.4

我观察到一个模态对话框存在问题,它不会阻止对其后面父窗口的访问。只有在运行进度对话框后再运行模式对话框时,才会发生这种情况。这种行为在某种程度上与自定义对话框有关。像wx.MessageDialog这样的集成对话框似乎没有这个问题

为了解决这个问题,我写了一个例子。前两个按钮打开“进度”或“模式”对话框并正常工作。第三个按钮按顺序打开两个对话框。在这种情况下,自定义对话框的模式功能不起作用,我可以访问并关闭大型机。这会导致多个问题

导入wx
类SomeDialog(wx.Dialog):
定义初始化(自身,父级):
对话框。初始化(self,parent,title='SomeDialog',
样式=wx。默认对话框(样式)
self.button_ok=wx.button(self,wx.ID_ok,size=(120,-1))
hsizer=wx.BoxSizer(wx.水平)
添加(self.button_ok,0,wx.ALL | wx.ALIGN_CENTER,10)
自我设定器(hsizer)
自我设置大小(自我最佳大小)
self.Layout()
类TestFrame(wx.Frame):
定义初始化(自):
wx.Frame.\uuuu init\uuuuu(self,None,-1,size=(400400))
self.button_progress=wx.button(self,-1,“显示进度”)
self.button_modal=wx.button(self,-1,“显示模式”)
self.button_both=wx.button(self,-1,‘同时显示’)
self.Bind(wx.EVT_按钮、self.on_按钮、self.BUTTON_进度)
self.Bind(wx.EVT_按钮、self.on_按钮、self.BUTTON_模式)
self.Bind(wx.EVT_按钮、self.on_按钮、self.BUTTON_按钮)
sizer=wx.BoxSizer()
sizer.Add(self.button\u进度)
sizer.Add(self.button\u模式)
sizer.Add(self.button\u两者)
自整定器(施胶器)
def on_按钮(自身,事件):
如果event.EventObject为self.button\u progress:
self.\u显示\u进度\u对话框()
elif event.EventObject是self.button_模式:
self.\u显示\u模式\u对话框()
其他:
self.\u显示\u进度\u对话框()
self.\u显示\u模式\u对话框()
定义显示进度对话框(自我):
最大值=10
dlg=wx.ProgressDialog('进度对话框示例','一些消息',
最大值=最大值,父项=自身,
样式=wx.PD_应用_模式| wx.PD_自动_隐藏)
继续=正确
计数=0
在保持和计数<最大值时:
计数+=1
wx.MilliSleep(250)
wx.收益率()
(继续,跳过)=数据更新(计数)
dlg.Destroy()
定义显示模式对话框(自):
使用SomeDialog(self)作为dlg:
dlg.CenterOnParent()
dlg.ShowModal()
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
app=wx.app()
frame=TestFrame()
frame.Show()
app.MainLoop()

如果这是wxpython框架中的一个问题,而不是我的实现中的问题,那么如果有人能为我提供一个解决方法来按顺序显示这样的对话框,那就太好了。

这在我看来像个bug。我不知道为什么会这样,但一个解决办法是使用

将“显示模式”对话框更改为:

def _show_modal_dialog(self):
    def _make_dialog():
        with SomeDialog(self) as dlg:
            dlg.CenterOnParent()
            dlg.ShowModal()

    wx.CallLater(50, _make_dialog) # 50 mils is arbitrary

似乎解决了对话的问题,没有采取行动。此解决方案的问题在于它是非阻塞的,这意味着必须等待对话框返回的任何代码都必须移动到对话框类中或作为回调传递到对话框

与此同时,我自己也找到了一个解决办法,我想与大家分享

我添加了一个捕获windows关闭事件的处理程序

class TestFrame(wx.Frame):
    def __init__(self):
        #...
        self.Bind(wx.EVT_CLOSE, self.on_close)
此事件函数检查某个子对话框是否打开且处于模态,并执行否决

def on_close(self, event):
    # In case any modal dialog is open, prevent the frame from closing.
    for children in (c for c in self.Children if isinstance(c, wx.Dialog)):
        if children.IsModal():
            event.Veto()
            return
    event.Skip()

这也只是一种变通方法,但我似乎在为我的用例工作

也许这是windows的问题。在linux上,虽然看起来我可以关闭主框架,但我不能。我可以确认windows 10、python 3.6、phoenix 4.0.4a1上存在此问题。感谢您确认此错误也出现在最新版本的wxpython和windows 10中。不幸的是,您提供的解决方案对我来说不适用或不实用,因为它改变了操作的顺序。调用_show_modal_dialog()后,程序流希望对应用程序状态进行一些更改。CallLater将延迟此更改,并且不再阻止以下程序流。当然,我可以解决这个问题,触发一些事件来通知更改,但我希望保持简单。
def on_close(self, event):
    # In case any modal dialog is open, prevent the frame from closing.
    for children in (c for c in self.Children if isinstance(c, wx.Dialog)):
        if children.IsModal():
            event.Veto()
            return
    event.Skip()