Search code examples
pythonpopupwxpython

How to SetFoucus to mainpanel or mainframe


This code is from one of the answer to the pop up window question in the website. I want to make the subframe to open when textctrl is clicked, and the mainframe closed at the same time, and the data is transferred back to the mainframe after clicking the 'save and close' button, the code now can open the subwindow and close the mainwindow, however, everytime I clicked 'save and close' button, the mainwindow appears in a sec and the subwindow is shown again. I assume that the focus is auto set to the textbox, so can you help to setfocus to the mainpanel or mainframe to solve the problem.

import wx
from wx.lib.pubsub import Publisher


########################################################################
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()
        Publisher().sendMessage(("show.mainframe"), msg)
        self.Close()


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

    #----------------------------------------------------------------------
    def __init__(self, parent):
        """Constructor"""
        wx.Panel.__init__(self, parent=parent)
        self.frame = parent

        Publisher().subscribe(self.showFrame, ("show.mainframe"))


        self.pubsubText = wx.TextCtrl(self, value="")

        self.pubsubText.Bind(wx.EVT_SET_FOCUS,self.hideFrame)


        Btn = wx.Button(self, label="Change")

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.pubsubText, 0, wx.ALL|wx.CENTER, 5)
        sizer.Add(Btn, 0, wx.ALL|wx.CENTER, 5)
        self.SetSizer(sizer)

    #----------------------------------------------------------------------
    def hideFrame(self, event):
        """"""
        self.frame.Hide()
        new_frame = OtherFrame()
        new_frame.Show()

    #----------------------------------------------------------------------
    def showFrame(self, msg):
        """
        Shows the frame and shows the message sent in the
        text control
        """
        self.pubsubText.SetValue(msg.data)
        frame = self.GetParent()
        frame.Show()

########################################################################
class MainFrame(wx.Frame):

    #----------------------------------------------------------------------
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, "Pubsub Tutorial")
        panel = MainPanel(self)

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

Solution

  • The reason this happens is that you are binding to the wrong event. The EVT_SET_FOCUS fires whenever the text control is in focus. It goes into focus when you click it. It also comes back into focus when you close the second frame and bring the first one back which is why you see the second frame again.

    Instead, you should bind to wx.EVT_LEFT_DOWN, which is a mouse event. Here's the updated code:

    import wx
    from wx.lib.pubsub import Publisher
    
    
    ########################################################################
    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()
            Publisher().sendMessage(("show.mainframe"), msg)
            self.Close()
    
    
    ########################################################################
    class MainPanel(wx.Panel):
        """"""
    
        #----------------------------------------------------------------------
        def __init__(self, parent):
            """Constructor"""
            wx.Panel.__init__(self, parent=parent)
            self.frame = parent
    
            Publisher().subscribe(self.showFrame, ("show.mainframe"))
    
    
            self.pubsubText = wx.TextCtrl(self, value="")
    
            #### NOTE CHANGE HERE ####
            self.pubsubText.Bind(wx.EVT_LEFT_DOWN,self.hideFrame)
    
    
            Btn = wx.Button(self, label="Change")
    
            sizer = wx.BoxSizer(wx.VERTICAL)
            sizer.Add(self.pubsubText, 0, wx.ALL|wx.CENTER, 5)
            sizer.Add(Btn, 0, wx.ALL|wx.CENTER, 5)
            self.SetSizer(sizer)
    
        #----------------------------------------------------------------------
        def hideFrame(self, event):
            """"""
            self.frame.Hide()
            new_frame = OtherFrame()
            new_frame.Show()
    
        #----------------------------------------------------------------------
        def showFrame(self, msg):
            """
            Shows the frame and shows the message sent in the
            text control
            """
            self.pubsubText.SetValue(msg.data)
            frame = self.GetParent()
            frame.Show()
    
    ########################################################################
    class MainFrame(wx.Frame):
    
        #----------------------------------------------------------------------
        def __init__(self):
            wx.Frame.__init__(self, None, wx.ID_ANY, "Pubsub Tutorial")
            panel = MainPanel(self)
    
    #----------------------------------------------------------------------
    if __name__ == "__main__":
        app = wx.App(False)
        frame = MainFrame()
        frame.Show()
        app.MainLoop()