smatter
smatter

Reputation: 29168

How to capture sub frame close event in main frame?

In WxPython, I have a new frame (ChildFrame) opening on a menu click on parent frame (ParentFrame). The child frame is for adding data to a config file. After the data is added (ie on close or on a button click in ChildFrame), I need to let the parent frame know that and refresh. How to do that in wxPython?

class ParentFrame(wx.Frame):
    def __init__(self,parent,id):
        ...
        self.Bind(wx.EVT_MENU, self.ShowChildFrame, None, ID_MENU_ITEM)


    def ShowChildFrame(self, event):
        self.child_frame= ChildFrame(parent=None, id=-1, title='New Frame Title')
        self.Bind(self.child_frame.EVT_CLOSE, self.OnChildFrameClose) #this does not work since no EVT_CLOSE is available
        self.child_frame.Show()

    def OnChildFrameClose(self, event):
        #do something

 class ChildFrame(wx.Frame):
    ...

Upvotes: 0

Views: 1150

Answers (2)

Yoriz
Yoriz

Reputation: 3625

You have to bind to the child frame instead of the parent frame and use the wx.EVT_CLOSE event.

import wx


class ParentFrame(wx.Frame):

    def __init__(self, *args, **kwargs):
        super(ParentFrame, self).__init__(*args, **kwargs)

    def ShowChildFrame(self):
        self.child_frame = wx.Frame(self, title='New Frame Title')
        self.child_frame.Bind(wx.EVT_CLOSE, self.OnChildFrameClose)
        self.child_frame.Show()

    def OnChildFrameClose(self, event):
        print 'do something'
        event.Skip()


app = wx.App()
frame = ParentFrame(None, title='Parent Frame')
frame.Show()
frame.ShowChildFrame()
app.MainLoop()

Upvotes: 0

Mike Driscoll
Mike Driscoll

Reputation: 33071

You can use PubSub. It comes with wxPython and allows you to subscribe to events. This will let you subscribe to a specific "close event". Then in your child frame, you can publish that it is closing when you catch the child frame's close event. The following tutorial might help:

Here's the code from the article (note: this requires wxPython 2.9 or higher):

import wx
from wx.lib.pubsub import pub 

########################################################################
class OtherFrame(wx.Frame):
    """"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, None, wx.ID_ANY, "Secondary Frame")
        panel = wx.Panel(self)

        msg = "Enter a Message to send to the main frame"
        instructions = wx.StaticText(panel, label=msg)
        self.msgTxt = wx.TextCtrl(panel, value="")
        closeBtn = wx.Button(panel, label="Send and Close")
        closeBtn.Bind(wx.EVT_BUTTON, self.onSendAndClose)

        sizer = wx.BoxSizer(wx.VERTICAL)
        flags = wx.ALL|wx.CENTER
        sizer.Add(instructions, 0, flags, 5)
        sizer.Add(self.msgTxt, 0, flags, 5)
        sizer.Add(closeBtn, 0, flags, 5)
        panel.SetSizer(sizer)

    #----------------------------------------------------------------------
    def onSendAndClose(self, event):
        """
        Send a message and close frame
        """
        msg = self.msgTxt.GetValue()
        pub.sendMessage("panelListener", message=msg)
        pub.sendMessage("panelListener", message="test2", arg2="2nd argument!")
        self.Close()

########################################################################
class MyPanel(wx.Panel):
    """"""

    #----------------------------------------------------------------------
    def __init__(self, parent):
        """Constructor"""
        wx.Panel.__init__(self, parent)
        pub.subscribe(self.myListener, "panelListener")

        btn = wx.Button(self, label="Open Frame")
        btn.Bind(wx.EVT_BUTTON, self.onOpenFrame)

    #----------------------------------------------------------------------
    def myListener(self, message, arg2=None):
        """
        Listener function
        """
        print "Received the following message: " + message
        if arg2:
            print "Received another arguments: " + str(arg2)

    #----------------------------------------------------------------------
    def onOpenFrame(self, event):
        """
        Opens secondary frame
        """
        frame = OtherFrame()
        frame.Show()

########################################################################
class MyFrame(wx.Frame):
    """"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, None, title="New PubSub API Tutorial")
        panel = MyPanel(self)
        self.Show()

#----------------------------------------------------------------------
if __name__ == "__main__":
    app = wx.App(False)
    frame = MyFrame()
    app.MainLoop()

Alternatively, you could create a subclass of wx.Dialog and use that instead of a frame. Then you can show the dialog modally and catch its closure the same way you do a built-in dialog.

Upvotes: 1

Related Questions