Search code examples
wxpythonsizer

Nesting sizers within a box using wxPython


I wish to make horizontal rows of labels and text fields, and place the rows inside a box with a label so they are grouped nicely. However, for some reason the box only extends around the last row in the series (see image below) I would like it to group all of the rows.

Is there an easier way to make a grouped and labelled interface like this?

Error with box label

The code to generate the above,

import wx

class ExamplePanel(wx.Panel):

    def __init__(self, parent):
        wx.Panel.__init__(self, parent)

        self.mainBox = wx.StaticBox(self, id=-1, label="Box Label")
        self.mainSizer = wx.StaticBoxSizer(self.mainBox, wx.VERTICAL)

        labels = ["A: ", "B: ", "C: "]
        for i, label in enumerate(labels):
            itemLabel = wx.StaticText(self, label=label)
            itemTextCtrl = wx.TextCtrl(self, value="placeholder")
            itemTextCtrl.SetForegroundColour(wx.LIGHT_GREY)
            rowSizer = wx.StaticBoxSizer(self.mainBox, wx.HORIZONTAL)
            rowSizer.Add(itemLabel, 0, wx.ALL, 0)
            rowSizer.Add(itemTextCtrl, 0, wx.ALL, 0)
            self.mainSizer.Add(rowSizer)

        self.SetSizer(self.mainSizer)
        self.mainSizer.Fit(self)

if __name__ == '__main__':
    app = wx.App(False)
    frame = wx.Frame(None)
    panel = ExamplePanel(frame)
    frame.Show()
    app.MainLoop()

Solution

  • The problem is that you do not want to nest a StaticBoxSizer. Instead, just use a normal BoxSizer for your rowSizers:

    import wx
    
    class ExamplePanel(wx.Panel):
    
        def __init__(self, parent):
            wx.Panel.__init__(self, parent)
    
            self.mainBox = wx.StaticBox(self, id=-1, label="Box Label")
            self.mainSizer = wx.StaticBoxSizer(self.mainBox, wx.VERTICAL)
    
            labels = ["A: ", "B: ", "C: "]
            for i, label in enumerate(labels):
                itemLabel = wx.StaticText(self, label=label)
                itemTextCtrl = wx.TextCtrl(self, value="placeholder")
                itemTextCtrl.SetForegroundColour(wx.LIGHT_GREY)
                rowSizer = wx.BoxSizer(wx.HORIZONTAL)
                rowSizer.Add(itemLabel, 0, wx.ALL, 0)
                rowSizer.Add(itemTextCtrl, 0, wx.ALL, 0)
                self.mainSizer.Add(rowSizer)
    
            self.SetSizer(self.mainSizer)
            self.mainSizer.Fit(self)
    
    if __name__ == '__main__':
        app = wx.App(False)
        frame = wx.Frame(None)
        panel = ExamplePanel(frame)
        frame.Show()
        app.MainLoop()
    

    Note that the box isn't tight around the widgets. I don't think it can be if it is the main sizer.