Search code examples
pythonwxpython

Why wx.Panel messed up the Sizer in this simple code?


I'm new to Python and this week I'm trying to use wxPython module to create GUIs. I think I understood how use sizers, but what happened to this code is intriguing me. Can someone help me to understand why?

This code should create a child panel for toolbar purposes and some content after it:

import wx

class Main_window (wx.Frame):
    def __init__(self):
        super(Main_window, self).__init__(parent = None, title = 'Some App')
        main_panel = wx.Panel(self)
        main_panel_sizer = wx.BoxSizer(wx.VERTICAL)

        # Calling panels
        toolbar = ToolBar(self)
        main_panel_sizer.Add(toolbar, 1, wx.EXPAND)
        button1 = wx.Button(main_panel, label='Button 1')
        main_panel_sizer.Add(button1, 0, wx.ALL|wx.ALIGN_LEFT)
        text = wx.StaticText(main_panel, label = 'Text 1')
        main_panel_sizer.Add(text, wx.ALL|wx.ALIGN_LEFT)

        # Final lines of constructor
        main_panel.SetSizer(main_panel_sizer)
        self.Show()

class ToolBar (wx.Panel):
    def __init__(self, parent):
        super().__init__(parent)
        self.SetBackgroundColour('blue')
        toolbar_sizer = wx.BoxSizer(wx.HORIZONTAL)
        button2 = wx.Button(self, label = 'Button 2')
        toolbar_sizer.Add(button2, 0, wx.ALIGN_LEFT)
        self.SetSizer(toolbar_sizer)

if __name__ == '__main__':
    app = wx.App()
    frame = Main_window()
    app.MainLoop()

But the ouput is a mess. Child panel, text and buttons are stacked in top. But if I comment the Toolbar calling:

import wx

class Main_window (wx.Frame):
    def __init__(self):
        super(Main_window, self).__init__(parent = None, title = 'Some App')
        main_panel = wx.Panel(self)
        main_panel_sizer = wx.BoxSizer(wx.VERTICAL)

        # Calling panels
        # toolbar = ToolBar(self)
        # main_panel_sizer.Add(toolbar, 1, wx.EXPAND)
        button1 = wx.Button(main_panel, label='Button 1')
        main_panel_sizer.Add(button1, 0, wx.ALL|wx.ALIGN_LEFT)
        text = wx.StaticText(main_panel, label = 'Text 1')
        main_panel_sizer.Add(text, wx.ALL|wx.ALIGN_LEFT)

        # Final lines of constructor
        main_panel.SetSizer(main_panel_sizer)
        self.Show()

class ToolBar (wx.Panel):
    def __init__(self, parent):
        super().__init__(parent)
        self.SetBackgroundColour('blue')
        toolbar_sizer = wx.BoxSizer(wx.HORIZONTAL)
        button2 = wx.Button(self, label = 'Button 2')
        toolbar_sizer.Add(button2, 0, wx.ALIGN_LEFT)
        self.SetSizer(toolbar_sizer)

if __name__ == '__main__':
    app = wx.App()
    frame = Main_window()
    app.MainLoop()

The sizer works again as it should. Someone can explain this? Seems witchcraft.

Thanks at advance.


Solution

  • Roughly speaking, you didn't apply the sizer to Main_window and ToolBar is a standalone panel.
    Below I assign a sizer to self and put into it the main_panel and toolbar, which both have their own sizers.
    Hope that clears things up. (Hint: it's not magic - well actually it is, courtesy of Mr Robin Dunn) :)

    import wx
    
    class Main_window (wx.Frame):
        def __init__(self):
            super(Main_window, self).__init__(parent = None, title = 'Some App')
            main_panel = wx.Panel(self)
            main_panel_sizer = wx.BoxSizer(wx.VERTICAL)
            main_sizer = wx.BoxSizer(wx.VERTICAL)
    
            # Calling panels
            toolbar = ToolBar(self)
    
            button1 = wx.Button(main_panel, label='Button 1')
            main_panel_sizer.Add(button1, 0, wx.ALL|wx.ALIGN_LEFT)
            text = wx.StaticText(main_panel, label = 'Text 1')
            main_panel_sizer.Add(text, wx.ALL|wx.ALIGN_LEFT)
    
            main_panel.SetSizer(main_panel_sizer)
            main_sizer.Add(toolbar, 1, wx.EXPAND)
            main_sizer.Add(main_panel)
            # Final lines of constructor
            self.SetSizer(main_sizer)
            self.Show()
    
    class ToolBar (wx.Panel):
        def __init__(self, parent):
            super().__init__(parent)
            self.SetBackgroundColour('blue')
            toolbar_sizer = wx.BoxSizer(wx.HORIZONTAL)
            button2 = wx.Button(self, label = 'Button 2')
            toolbar_sizer.Add(button2, 0, wx.ALIGN_LEFT)
            self.SetSizer(toolbar_sizer)
    
    if __name__ == '__main__':
        app = wx.App()
        frame = Main_window()
        app.MainLoop()
    

    enter image description here