单击wx.Dialog中的“确定”或“取消”按钮时,为什么没有触发EVT_CLOSE?

时间:2014-01-27 18:12:13

标签: wxpython wxwidgets

我有一个wx.Dialog子类,当用户单击OK按钮时需要执行几个清理操作。 wx.Dialog documentation表示单击“确定”或“取消”应发出EVT_CLOSE事件:

  

EVT_CLOSE:用户或以编程方式关闭对话框(请参阅Window.Close)。用户可以单击关闭按钮(通常是标题栏右上角的“X”)生成此事件(如果它存在(请参阅CLOSE_BOX样式)或单击带有ID_CANCEL或ID_OK ID的按钮。

然而,我正在使用WX 2.9.5.0(通过wxPython),当我在此测试应用程序中单击“确定”或“取消”时,不会调用OnClose方法。单击系统的关闭按钮(我正在使用OS X)时调用OnClose。我是否实现了此事件处理错误或者wx.Dialog是否真的不符合其文档?在后一种情况下,拦截单击“确定”按钮的最佳方法是什么?

from __future__ import print_function
import wx

class TestDialog(wx.Dialog):
    def __init__(self, parent):
        wx.Dialog.__init__(self, parent, title='Test Dialog')

        sizer = wx.BoxSizer(wx.VERTICAL)

        message = wx.StaticText(self, wx.NewId(), 'This is some dummy text')
        sizer.Add(message)

        ok_button = wx.Button(self, wx.ID_OK, 'OK')
        cancel_button = wx.Button(self, wx.ID_CANCEL, 'Cancel')

        btn_sizer = self.CreateStdDialogButtonSizer(wx.OK | wx.CANCEL)
        btn_sizer.Add(cancel_button)
        btn_sizer.Add(ok_button)
        sizer.Add(btn_sizer)

        self.SetSizer(sizer)

        self.Bind(wx.EVT_CLOSE, self.OnClose)

    def OnClose(self, event):
        print('In OnClose')
        event.Skip()

if __name__ == '__main__':
    app = wx.App(False)

    dialog = TestDialog(None)
    result = dialog.ShowModal()
    print('Result: {}'.format(result))

4 个答案:

答案 0 :(得分:4)

单击模式对话框上的“确定”或“取消”按钮时,对话框未使用Close关闭,而是以EndModal结束,因此不会发送EVT_CLOSE事件。正常完成模态对话框时需要运行的代码通常在调用ShowModal之后放置。在这种情况下,我认为文档不正确。

OTOH,如果对话框显示为无模式(使用Show而非ShowModal),则应使用Close关闭它们,您将获得EVT_CLOSE事件。< / p>

答案 1 :(得分:1)

这是因为将调用Destroy()而不是Close()。没有Close(),EVT_CLOSE不会被引发。您可以尝试以下代码。

import wx
class TestDialog(wx.Dialog):
    def __init__(self, parent):
        wx.Dialog.__init__(self, parent, title='Test Dialog')

        sizer = wx.BoxSizer(wx.VERTICAL)

        message = wx.StaticText(self, wx.NewId(), 'This is some dummy text')
        sizer.Add(message)

        ok_button = wx.Button(self, wx.ID_OK, 'OK')
        cancel_button = wx.Button(self, wx.ID_CANCEL, 'Cancel')

        btn_sizer = self.CreateStdDialogButtonSizer(wx.OK | wx.CANCEL)
        btn_sizer.Add(cancel_button)
        btn_sizer.Add(ok_button)
        sizer.Add(btn_sizer)

        self.SetSizer(sizer)
        self.Bind(wx.EVT_CLOSE, self.OnClose)
        self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)

    def OnClose(self, event):
        print 'In OnClose'
        event.Skip()

    def OnDestroy(self, event):
        print 'In OnDestroy'
        event.Skip()

if __name__ == '__main__':
    app = wx.App(False)
    frame = wx.Frame(None)
    frame.Show()
    dialog = TestDialog(frame)
    result = dialog.ShowModal()
    dialog.Close(True)
    print 'Result: {}'.format(result)
    app.MainLoop()

答案 2 :(得分:0)

对于任何寻找类似问题答案的人...你可以捕获OK按钮点击事件,只在你想要关闭表单时调用event.Skip()。如果你不打电话,就不会打电话给Destroy()。我不知道如何在wxPython中编写它,但在C ++中它将是:

//

答案 3 :(得分:0)

我只是遇到了这个问题,并根据答案here,提出了以下解决方案。已使用wxPython 4.1.0和python 3.8.5进行了测试。

实质上,wx.EVT_BUTTON窗口中的所有wx.Dialog事件都绑定到wx.Dialog窗口中的方法。在该方法中,将单击的按钮的ID与wx.Dialog中用于创建按钮的ID进行比较,并据此采取措施。

在下面的示例中,单击“确定”按钮将生成一个随机数。 wx.Dialog仅在随机数> 0.5时关闭。

import random
import wx


class Example(wx.Frame):
    """Main window """
    #region ---> Instance Setup
    def __init__(self, parent):
        #region ---> Initial setup
        super().__init__(
            parent, 
            title = 'Intercept wx.Dialog button events',
            size  = (260, 180),
        )
        #endregion ---> Initial setup

        #region ---> Widgets
        self.btn = wx.Button(self, label = 'Show Dialog Window')
        #endregion ---> Widgets

        #region ---> Sizers
        self.Sizer = wx.BoxSizer()
        self.Sizer.Add(self.btn, 0, wx.ALIGN_CENTER|wx.ALL, 5)
        self.SetSizer(self.Sizer)
        #endregion ---> Sizers

        #region ---> Bind
        self.btn.Bind(wx.EVT_BUTTON, self.OnDialog)
        #endregion ---> Bind

        #region ---> Show
        self.Centre()
        self.Show()
        #endregion ---> Show
    #---
    #endregion ---> Instance Setup

    #region ---> Class methods
    def OnDialog(self, event):
        """"""
        with MyDialog(self) as dlg:
            if dlg.ShowModal() == wx.ID_OK:
                print("Dialog closed with OK - Message from Main Window")
                print("")
            else:
                print("Dialog closed with Cancel - Message from Main Window")
                print("")
    #---
    #endregion ---> Class methods
#---

class MyDialog(wx.Dialog):
    """"""
    #region ---> Instance Setup
    def __init__(self, parent):
        #region ---> Initial setup
        super().__init__(
            parent, 
            title = 'My Dialog',
            size  = (220, 90),
        )
        #endregion ---> Initial setup

        #region ---> Sizer
        self.btnSizer = self.CreateStdDialogButtonSizer(
            wx.OK|wx.CANCEL
        )

        self.Sizer = wx.BoxSizer()
        self.Sizer.Add(self.btnSizer, 0, wx.ALIGN_CENTER|wx.ALL, 5)

        self.SetSizer(self.Sizer)
        #endregion ---> Sizer

        #region ---> Show
        self.CentreOnParent()
        #endregion ---> Show

        #region ---> Bind
        self.Bind(wx.EVT_BUTTON, self.OnButton) # HERE IS THE TRICK, Get all Button events
        #endregion ---> Bind
    #---
    #endregion ---> Instance Setup

    #region ---> Class methods
    def OnButton(self, event):
        """Process the OK button click"""
        #region ---> Get the id of the clicked button 
        clicked_button_id = event.GetEventObject().GetId()
        #endregion ---> Get the id of the clicked button 

        #region ---> Identify the clicked button & act accordingly
        if clicked_button_id == wx.ID_OK:
            print("Processing OK button click")
            if (n := random.random()) > 0.5:
                #--> Everything fine, window will close
                print(n, "> 0.5. Ok, closing window")
                pass
            else:
                #--> Error, window will remain open
                print(n, "< 0.5. Not Ok, window remains open")
                return False 
        else:
            print("Processing Cancel button click")
        #endregion ---> Identify the clicked button & act accordingly

        #region ---> Skip event to make sure default behavior is executed
        event.Skip()
        #endregion ---> Skip event to make sure default behavior is executed
    #---
    #endregion ---> Class methods
#---

if __name__ == '__main__':

    app = wx.App()
    Example(None)
    app.MainLoop()