Search code examples
pythonwxpython

wxPython: Switching between multiple panels with a button


I would like to have two (I will add more later) panels that occupy the same space within the frame and for them to be shown/hidden when the respective button is pressed on the toolbar, "mListPanel" should be the default. Currently the settings panel is shown when the application is launched and the buttons don't do anything. I've searched and tried lots of stuff for hours and still can't get it to work. I apologise if it's something simple, I've only started learning python today.

This is what the code looks like now:

    import wx

    class mListPanel(wx.Panel):
        def __init__(self, parent):
            wx.Panel.__init__(self, parent=parent)
                #wx.StaticText(self, -1, label='Search:')#, pos=(10, 3))
                #wx.TextCtrl(self, pos=(10, 10), size=(250, 50))

    class settingsPanel(wx.Panel):
        def __init__(self, parent):
            wx.Panel.__init__(self, parent=parent)

    class bifr(wx.Frame):
        def __init__(self):
            wx.Frame.__init__(self, None, wx.ID_ANY, "Title")

            self.listPanel = mListPanel(self)
            self.optPanel = settingsPanel(self)

            menuBar = wx.MenuBar()
            fileButton = wx.Menu()
            importItem = wx.Menu()
            fileButton.AppendMenu(wx.ID_ADD, 'Add M', importItem)
            importItem.Append(wx.ID_ANY, 'Import from computer')
            importItem.Append(wx.ID_ANY, 'Import from the internet')
            exitItem = fileButton.Append(wx.ID_EXIT, 'Exit')
            menuBar.Append(fileButton, 'File')
            self.SetMenuBar(menuBar)
            self.Bind(wx.EVT_MENU, self.Quit, exitItem)

            toolBar = self.CreateToolBar()
            homeToolButton = toolBar.AddLabelTool(wx.ID_ANY, 'Home', wx.Bitmap('icons/home_icon&32.png'))
            importLocalToolButton = toolBar.AddLabelTool(wx.ID_ANY, 'Import from computer', wx.Bitmap('icons/comp_icon&32.png'))
            importToolButton = toolBar.AddLabelTool(wx.ID_ANY, 'Import from the internet', wx.Bitmap('icons/arrow_bottom_icon&32.png'))
            settingsToolButton = toolBar.AddLabelTool(wx.ID_ANY, 'settings', wx.Bitmap('icons/wrench_plus_2_icon&32.png'))
            toolBar.Realize()

            self.Bind(wx.EVT_TOOL, self.switchPanels(), settingsToolButton)
            self.Bind(wx.EVT_TOOL, self.switchPanels(), homeToolButton)
            self.Layout()

        def switchPanels(self):
            if self.optPanel.IsShown():
                self.optPanel.Hide()
                self.listPanel.Show()
                self.SetTitle("Home")
            elif self.listPanel.IsShown():
                self.listPanel.Hide()
                self.optPanel.Show()
                self.SetTitle("Settings")
            else:
                self.SetTitle("Error")
            self.Layout()

        def Quit(self, e):
            self.Close()

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

Solution

  • first off, i would highly suggest that you learn about wxpython sizers and get a good understanding of them (they're really not that hard the understand) as soon as possible before delving deeper into wxpython, just a friendly tip :).

    as for your example, a few things: when your'e not using sizers, you have to give size and position for every window or else they just wont show, so you'd have to change your panel classes to something like this (again this is only for demonstration, you should be doing this with wx.sizers, and not position and size):

    class mListPanel(wx.Panel):
        def __init__(self, parent):
            wx.Panel.__init__(self, parent=parent,pos=(0,100),size=(500,500))
    
    class settingsPanel(wx.Panel):
        def __init__(self, parent):
            wx.Panel.__init__(self, parent=parent,pos=(0,200),size (1000,1000))
    

    further more, when binding an event it should look like this:

    self.Bind(wx.EVT_TOOL, self.switchPanels, settingsToolButton)
    self.Bind(wx.EVT_TOOL, self.switchPanels, homeToolButton)
    

    notice how I've written only the name of the function without the added (), as an event is passed to it, you cant enter your own parameters to a function emitted from an event (unless you do it with the following syntax lambda e:FooEventHandler(paramaters))

    and the event handler (function) should look like this:

    def switchPanels(self, event):
        if self.optPanel.IsShown():
            self.optPanel.Hide()
            self.listPanel.Show()
            self.SetTitle("Home")
        elif self.listPanel.IsShown():
            self.listPanel.Hide()
            self.optPanel.Show()
            self.SetTitle("Settings")
        else:
            self.SetTitle("Error")
        self.Layout()
    

    there should always be a second parameter next to self in functions that are bind to event as the event object is passes there, and you can find its associated methods and parameters in the documentation (in this example it is the wx.EVT_TOOL).