wxPython Sizers Tutorial: Using a GridBagSizer

In this tutorial, I will take my code from the GridSizer tutorial I wrote the other day and heavily modify it to display oddly shaped widgets in a GridBagSizer. The GridBagSizer is the most complex of the sizers. It subclasses the FlexGridSizer, so you can use all of it’s parent’s methods as well as those that the GridBagSizer adds. See the docs or use Python’s help() functionality for more information on said methods.

Here’s how you instantiate the GridBagSizer:

 bagSizer    = wx.GridBagSizer(hgap=5, vgap=5)

You’ll notice that you do not need to specify rows or columns when you create an instance of the GridBagSizer. When you get to the Add() function, you’ll notice that it adds the span parameter. This parameter allows you to specify if the widget can specify multiple rows, columns or both. Before I actually start doing that though, I’ll go over the odd-shaped widgets that we’ll be adding to the rows.

The first one I’m going to add is a RadioBox. First, you need to create a list of values for the RadioBox. Here’s the setup for this interesting widget:

rb = wx.RadioBox(parent, id, label, pos, size, choices, majorDimension,
                        style, validator, name)

There’s only two parameters here that I think need additional explanation: choices and majorDimension. The “choices” parameter refers to the list of values you create. The majorDimension parameter is used to state the size of one dimension, either rows or columns, which is based on the style flag you use (either wx.RA_SPECIFY_COLS or wx.RA_SPECIFY_ROWS). It defaults to columns. If you want the opposite effect, then use the wx.RA_SPECIFY_ROWS flag. See the “wxPython in Action” book, page 215 for more information.

The other widget I’ll use is a multiline TextCtrl. All you need to do to make a TextCtrl go multiline is add the style flag, wx.TE_MULTILINE. Once we have these added and the proper flags are in place, you should see something like this:

Ok. Let’s look at the code:

import wx

class MyForm(wx.Frame):

    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, 'My Form') 

        # Add a panel so it looks the correct on all platforms
        self.panel = wx.Panel(self, wx.ID_ANY)

        bmp = wx.ArtProvider.GetBitmap(wx.ART_INFORMATION, wx.ART_OTHER, (16, 16))
        font = wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD)
        titleIco = wx.StaticBitmap(self.panel, wx.ID_ANY, bmp)
        title = wx.StaticText(self.panel, wx.ID_ANY, 'My Title')

        # 1st row of widgets
        bmp = wx.ArtProvider.GetBitmap(wx.ART_TIP, wx.ART_OTHER, (16, 16))
        inputOneIco = wx.StaticBitmap(self.panel, wx.ID_ANY, bmp)
        labelOne = wx.StaticText(self.panel, wx.ID_ANY, 'Name')
        inputTxtOne = wx.TextCtrl(self.panel, wx.ID_ANY,'')

        sampleList = ['zero', 'one', 'two', 'three', 'four', 'five',
                      'six', 'seven', 'eight']
        rb = wx.RadioBox(
                self.panel, wx.ID_ANY, "wx.RadioBox", wx.DefaultPosition,
                wx.DefaultSize, sampleList, 2, wx.RA_SPECIFY_COLS

        # 2nd row of widgets
        multiTxt = wx.TextCtrl(self.panel, wx.ID_ANY, '',
        sampleList = ['one', 'two', 'three', 'four']
        combo = wx.ComboBox(self.panel, wx.ID_ANY, 'Default', wx.DefaultPosition,
                            (100,-1), sampleList, wx.CB_DROPDOWN)

        # Create the sizers
        topSizer    = wx.BoxSizer(wx.VERTICAL)
        titleSizer  = wx.BoxSizer(wx.HORIZONTAL)
        bagSizer    = wx.GridBagSizer(hgap=5, vgap=5)

        # Add widgets to sizers
        titleSizer.Add(titleIco, 0, wx.ALL, 5)
        titleSizer.Add(title, 0, wx.ALL, 5)

        bagSizer.Add(inputOneIco, pos=(0,0),
        bagSizer.Add(labelOne, pos=(0,1),
        bagSizer.Add(inputTxtOne, pos=(0,2),
        bagSizer.AddGrowableCol(2, 0)        
        bagSizer.Add(rb, pos=(0,3), span=(3,2))

        bagSizer.Add(multiTxt, pos=(1,0), 
        bagSizer.Add(combo, pos=(1,1),

        # Add sub-sizers to topSizer
        topSizer.Add(titleSizer, 0, wx.CENTER)
        topSizer.Add(wx.StaticLine(self.panel), 0, wx.ALL|wx.EXPAND, 5)
        topSizer.Add(bagSizer, 0, wx.ALL|wx.EXPAND, 5)

        # SetSizeHints(minW, minH, maxW, maxH)

# Run the program
if __name__ == '__main__':
    app = wx.PySimpleApp()
    frame = MyForm().Show()

One of the first things you’ll notice is that when I add my icon and label to the GridBagSizer, I make sure to pass the wx.ALIGN_CENTER_VERTICAL flag so that they will be centered with the first text control. You’ll also notice the “pos” parameter. This tells the GridBagSizer where to put the widget. So pos=(0,0) means to put the widget in row 0, column 0.

Other things to note:

  • The first text control gets a border of 10 so it’s not “fat” (too high)
  • To allow the text control to resize, you need to make the column “growable” by using the AddGrowableCol() method of the GridBagSizer.
  • Take note of which widgets I gave the span attribute to. Remember, span(row,col) starts wherever the widget it applies to is. So if the widget is at (0,0) and you tell it to span(2,0), it will span 2 rows, but zero columns.

I didn’t use all of the GridBagSizer’s methods in this article. I encourage the reader to check out the methods SetFlexibleDirection() and SetNonFlexibleGrowMode() as they can be helpful in controlling which direction a row or column stretches.


Further Reading
GridBagSizers on the Wiki

2 thoughts on “wxPython Sizers Tutorial: Using a GridBagSizer”

  1. hi, thanks for your code, pay attention that downloading the code will mess up the “‘” simbol that must be replace manually.
    At least on Debian and Iceweasel

  2. hi, thanks for your code, pay attention that downloading the code will mess up the “‘” simbol that must be replace manually.
    At least on Debian and Iceweasel

Comments are closed.