In this tutorial, I will take my code from the GridSizerTutorial 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’)
        title.SetFont(font)
 
        # 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, ”,
                               size=(200,100),
                               style=wx.TE_MULTILINE)
        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),
                     flag=wx.ALL|wx.ALIGN_CENTER_VERTICAL,
                     border=5)
        bagSizer.Add(labelOne, pos=(0,1),
                     flag=wx.ALL|wx.ALIGN_CENTER_VERTICAL,
                     border=5)
        bagSizer.Add(inputTxtOne, pos=(0,2),
                     flag=wx.EXPAND|wx.ALL,
                     border=10)
        bagSizer.AddGrowableCol(2, 0)
        bagSizer.Add(rb, pos=(0,3), span=(3,2))
 
        bagSizer.Add(multiTxt, pos=(1,0),
                     flag=wx.ALL,
                     border=5)
        bagSizer.Add(combo, pos=(1,1),
                     flag=wx.ALL,
                     border=5)
 
        # 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)
 
        self.panel.SetSizer(topSizer)
 
        # SetSizeHints(minW, minH, maxW, maxH)
        self.SetSizeHints(250,200,700,300)
        topSizer.Fit(self)
 
# Run the program
if __name__ == ‘__main__’:
    app = wx.PySimpleApp()
    frame = MyForm().Show()
    app.MainLoop()

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:

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

GridBagSizerTutorial (last edited 2008-05-28 00:17:25 by 208)

NOTE: To edit pages in this wiki you must be a member of the TrustedEditorsGroup.