wxPython: Wrap Widgets with WrapSizer

wxPython 2.9 introduced the world to a new type of sizer that can take widgets and automatically make them “wrap” around as you resize the frame. That sizer is known as wx.WrapSizer. For some reason, it is relatively unknown, so we’ll spend a few minutes going over how to use it in this article.

To follow along with this tutorial, you will need to have wxPython 2.9 or greater. Once you’ve got that, we can continue.

Using WrapSizer

wxWrapSizerDemo

The wx.WrapSizer widget works in much the same way as a wx.BoxSizer. All you need to do to use it is to instantiate it and add widgets to it. Let’s take a look at a simple program:

import random
import wx
from wx.lib.buttons import GenButton

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

    #----------------------------------------------------------------------
    def __init__(self, parent):
        """Constructor"""
        wx.Panel.__init__(self, parent)
        
        text = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        sizer = wx.WrapSizer()
        for letter in text:
            btn = GenButton(self, label=letter)
            r = random.randint(128, 255)
            g = random.randint(128, 255)
            b = random.randint(128, 255)
            btn.SetBackgroundColour(wx.Colour(r,g,b))
            btn.Refresh()
            sizer.Add(btn, 0, wx.ALL, 5)
    
        self.SetSizer(sizer)
    
########################################################################
class MyFrame(wx.Frame):
    """"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, None, title="WrapSizers", size=(400,500))
        panel = MyPanel(self)
        self.Show()
    
#----------------------------------------------------------------------
if __name__ == "__main__":
    app = wx.App(False)
    frame = MyFrame()
    app.MainLoop()

Here we create an instance of our sizer and then loop over the letters in the alphabet, creating a button for each letter. We also change the background color of each button to add a little variety. If you haven’t guessed yet, this example is based on the wxPython demo example. You will notice that as you resize the frame, the buttons will rearrange themselves as best they can. Sometimes, they may even change size a bit. Let’s learn a bit more about this sizer!

The wx.WrapSizer can be told its orientation and you can pass it flags at instantiation. The orientation flags are wx.HORIZONTAL and wx.VERTICAL. Horizontal is the default. According to the documentation “the flags parameter can be a combination of the values EXTEND_LAST_ON_EACH_LINE which will cause the last item on each line to use any remaining space on that line and REMOVE_LEADING_SPACES which removes any spacer elements from the beginning of a row.” The WrapSizer also has four additional methods beyond the normal wx.Sizer method: CalcMin (calculates minimal size), InformFirstDirection (appears not be used), IsSpaceItem (can be used to treat some normal items as spacers) and RecalcSizes (implements the calculation of a box sizer’s dimensions and then sets the size of its children).

That just about wraps up all the information on this widget. Hopefully you will find many good uses for this relatively unknown sizer in your own projects.

Note: This code was tested using wxPython 2.9.3 (classic) with Python 2.7.3 on Windows 7.

2 thoughts on “wxPython: Wrap Widgets with WrapSizer”

  1. How to add a vertical Scrollbar ? (I want to keep the nice WrapSizer behaviour, but if not enough room, a vertical scrollbar should be added …)

Comments are closed.