Search code examples
pythonuser-interfacelayoutwxpythonwxwidgets

Padding in Panel and static text wrap in wxpython


I would like to have a layout something like this

enter image description here

There is a Main Panel just inside the frame with blank padding in the left and right which another Sub Panel located in the middle. A Static Text element located at the top of Sub Panel and it should wrap properly when changing the window size.

My code snippet listed as following

import wx

class MyPanel(wx.Panel):
    def __init__(self, parent):
        super(MyPanel, self).__init__(parent)

        self.hsizer = wx.BoxSizer()
        self.hsizer.AddStretchSpacer()

        self.panel = wx.Panel(self)
        self.panel.SetSize((350, -1))

        self.vsizer = wx.BoxSizer(wx.VERTICAL)

        label = (
            "This is a long scentence that I want it wrapped properly, "
            "but it doesn't seem to work at work. "
            "I prefer if you guys can give any sugeestions or help. "
            "For Long Long Long Long Long scentence."
        )
        style = wx.ALIGN_LEFT
        self.static_text = wx.StaticText(self, label=label, style=style)
        self.vsizer.Add(self.static_text, flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
        self.static_text.Wrap(self.panel.Size[0])
        self.static_text.SetAutoLayout(True)

        self.panel.SetSizer(self.vsizer)
        self.hsizer.Add(self.panel, flag=wx.ALIGN_CENTER)
        self.hsizer.AddStretchSpacer()
        self.SetSizer(self.hsizer)
        self.Layout()
        print self.Size
        print self.panel.Size

if __name__ == '__main__':
    app = wx.App()
    frame = wx.Frame(None)
    sizer = wx.BoxSizer()
    sizer.Add(MyPanel(frame), flag=wx.EXPAND)
    frame.SetSizer(sizer)
    frame.Show()
    app.MainLoop()

Currently, not only the Sub Panel is not located in the middle, but also the text in static text doesn't wrap properly when changing the window size. Any suggestions to make it work?


Solution

  • It is often helpful to set some background colours while trying to implement a layout with sizers, that way it's easy to visualize where the boundaries are, and how they behave while resizing things. Another helpful tool is the Widget Inspection Tool. For example:

    import wx
    
    class MyPanel(wx.Panel):
        def __init__(self, parent):
            super(MyPanel, self).__init__(parent)
            self.SetBackgroundColour('pink')
    
            self.hsizer = wx.BoxSizer()
            self.hsizer.AddStretchSpacer()
    
            self.panel = wx.Panel(self)
            self.panel.SetSize((350, -1))
            self.panel.SetBackgroundColour('green')
    
            self.vsizer = wx.BoxSizer(wx.VERTICAL)
    
            label = (
                "This is a long scentence that I want it wrapped properly, "
                "but it doesn't seem to work at work. "
                "I prefer if you guys can give any sugeestions or help. "
                "For Long Long Long Long Long scentence."
            )
            style = wx.ALIGN_LEFT
            self.static_text = wx.StaticText(self, label=label, style=style)
            self.static_text.SetBackgroundColour('yellow')
    
            self.vsizer.Add(self.static_text, flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
            self.static_text.Wrap(self.panel.Size[0])
            self.static_text.SetAutoLayout(True)
    
            self.panel.SetSizer(self.vsizer)
            self.hsizer.Add(self.panel, flag=wx.ALIGN_CENTER)
            self.hsizer.AddStretchSpacer()
            self.SetSizer(self.hsizer)
    
    if __name__ == '__main__':
        app = wx.App()
        frame = wx.Frame(None)
        frame.SetBackgroundColour('sky blue')
        sizer = wx.BoxSizer()
        sizer.Add(MyPanel(frame), flag=wx.EXPAND)
        frame.SetSizer(sizer)
        frame.Show()
    
        import wx.lib.inspection
        wx.lib.inspection.InspectionTool().Show()
    
        app.MainLoop()
    

    After running that we can see that things don't really match your sketch of the layout, that things like the text don't change size or position when the frame is resized, and that the MyPanel (the pink one) is also not resizing to fill the frame. Also, it appears from the code that you intend the text to be the child of the green panel (self.panel) but looking at the colours at runtime it obviously is not. Looking again at the code we see that it is being created with self as the parent instead of self.panel.

    So after a few more tweaks to address those issues, we end up with this code:

    import wx
    
    class MyPanel(wx.Panel):
        def __init__(self, parent):
            super(MyPanel, self).__init__(parent)
            self.SetBackgroundColour('pink')
    
            self.hsizer = wx.BoxSizer()
            self.hsizer.AddStretchSpacer()
    
            self.panel = wx.Panel(self)
            self.panel.SetSize((350, -1))
            self.panel.SetBackgroundColour('green')
    
            self.vsizer = wx.BoxSizer(wx.VERTICAL)
    
            label = (
                "This is a long scentence that I want it wrapped properly, "
                "but it doesn't seem to work at work. "
                "I prefer if you guys can give any sugeestions or help. "
                "For Long Long Long Long Long scentence."
            )
            style = wx.ALIGN_LEFT
            self.static_text = wx.StaticText(self.panel, label=label, style=style)
            self.static_text.SetBackgroundColour('yellow')
    
            self.vsizer.Add(self.static_text,
                            flag=wx.EXPAND | wx.ALL | wx.ALIGN_TOP, border=5)
            self.static_text.Wrap(self.panel.Size[0])
    
            self.panel.SetSizer(self.vsizer)
            self.hsizer.Add(self.panel, 1, flag=wx.EXPAND)
            self.hsizer.AddStretchSpacer()
            self.SetSizer(self.hsizer)
    
    if __name__ == '__main__':
        app = wx.App()
        frame = wx.Frame(None)
        frame.SetBackgroundColour('sky blue')
        sizer = wx.BoxSizer()
        sizer.Add(MyPanel(frame), 1, flag=wx.EXPAND)
        frame.SetSizer(sizer)
        frame.Show()
    
        import wx.lib.inspection
        wx.lib.inspection.InspectionTool().Show()
    
        app.MainLoop()
    

    Finally, if you want the text to be rewrapped when the size gets narrower than 350 then you'll need to do something like catch EVT_SIZE events and call Wrap again with a different size when needed.