Foreword

The purpose of this tutorial is to get you started with the wxPython toolkit, from the basics to the advanced topics. It has lots of code examples, not much talking. After that, you will be able to dig in yourself.

status update. (april 2007) All my work on wxPython tutorial has been moved to my website http://www.zetcode.com/wxpython here I shall not add any more examples. If I find myself some time, I will do some polishing.

wxPython API

wxPython API is a set of functions and widgets. Widgets are essential building blocks of a GUI application. Under Windows widgets are calles controls. We can roughly divide programmers into two groups. They code applications or libraries. In our case, wxPython is a library that is used by application programmers to code applications. Technically, wxPython is a wrapper over a C++ GUI API called wxWidgets. So it is not a native API. e.g. not written directly in Python. The only native GUI library for an interpreted language that I know is Java's Swing library.

In wxPython we have lot's of widgets. These can be divided into some logical groups.

Base Widgets

These widgets provide basic functionality for derived widgets. They are usually not used directly.

wx.Window

wx.Control

wx.ControlWithItem

Top level Widgets

These widgets exist independently of each other.

wx.Frame

wx.MDIParentFrame

wx.MDIChildFrame

wx.Dialog

wx.PopupWindow

Containers

Containers contain other widgets. These widgets are called children.

wx.Panel

wx.Notebook

wx.ScrolledWindow

wx.SplitterWindow

Dynamic Widgets

These widgets can be edited by users.

wx.Button

wx.BitmapButton

wx.Choice

wx.ComboBox

wx.CheckBox

wx.Grid

wx.ListBox

wx.RadioBox

wx.RadioButton

wx.ScrollBar

wx.SpinButton

wx.SpinCtrl

wx.Slider

wx.TextCtrl

wx.ToggleButton

Static Widgets

These widgets display informatin. They cannot be edited by user.

wx.Gauge

wx.StaticText

wx.StaticBitmap

wx.StaticLine

wx.StaticBox

Other Widgets

These widgets implement statusbar, toolbar and menubar in an application.

We create a frame widget. The window pops up only if we call Show() method on a widget.

frame = wx.Frame(None, -1, "simple.py")
frame.Show()

The last line enters a Mainloop. A mainloop is an endless cycle that catches up all events coming up to your application. It is an integral part of any windows GUI application.

app.MainLoop()

Although the code is very simple, you can do a lot of things with your window. You can maximize it, minimize it, move it, resize it. All these things have been already done.

Figure: simple.py

wx.Window

wx.Window is a base class out of which many widgets inherit. For instance, the wx.Frame widget inherits from wx.Window. Technically it means that we can use wx.Window's methods for all descendants. We will introduce here some of its methods.

SetTitle(string title) - Sets the window's title. Applicable only to frames and dialogs.

SetToolTip(wx.ToolTip tip) - Attaches a tooltip to the window.

SetSize(wx.Size size) - Sets the size of the window.

SetPosition(wx.Point pos) - Positions the window to given coordinates

Show(show=True) - Shows or hides the window. show parameter can be True or False.

We create a 'This is a frame' tooltip. The cursor is set to a magnifier cursor. Possible cursor id's: are listed below We position the window to the upper left corner and size it to 300x250 pixels. Title is set to 'simple2.py'.

wx.Frame

wx.Frame is a container widget. It means that it can contain other widgets. It has the following constructor:

A constructor is a special kind of a function. It is called when an object is created. For us it is only important that when we want to create a new widget, we simply call its constructor. Python enables parameters with default values. So the only obligatory parameters in wx.Frame are parent, id and title. If you specify all values of the parameters in order, you don't need to specify the parameter names. For example you want to create a wx.Frame widget, which has no parent, its identifier is 100, the title is 'Title', the position is (100,50) and the size is (100,100).

Icon's name is Tipi.ico. The icon is located in current directory. First parameter of an icon's constructor is the file name. Second parameter specifies the file type.

As you have noticed, the structure of our application has changed. This is a standard in Python programs. In Python programs __name__ is a special variable. More complicated programs consist of several files. There is usually only one file, which launches the application. For this file, Python sets the __name__ variable to '__main__'. This happens when you launch an application from the command line or when you click on the file. So when you click on the icon.py file or you launch it from the command line, the __name__ variable equals '__main__'. Then function main() is called.

Figure: icon.py

wx.MenuBar

To set up a menubar in your wxPython application is pretty simple. We will discuss adding menus to menubar, adding submenus to existing menus. Each menu consists of menuitems. Menuitems can be normal items, check items or radio items.

We now discuss how to respond to user actions. We will touch on it only briefly and explain it later in more detail.

So when a user of our application selects a menu item, an event is generated. We must provide an event handler, that will react to this event accordingly. Handling events in wxPython is the most elegant and simple that I have seen so far. When we look into the reference book, we find wx.EVT_MENU handler under Event handling section.

Suppose we want to add an event handler to our quit menu item.

wx.EVT_MENU(self, 105, self.OnQuit )

We need to provide three pieces of information. The object, where we bind our event handler. In our case self, the application's main object. The id of the corresponding menu item. And the method name, which will do our job.

The method which will react to user actions has two parameters. The first one is the object where this method is defined. The second one is the generated event. This time, we do without it. We simply close our application.

def OnQuit(self, event):
self.Close()

The following script demonstrates various menu items, submenu and one simple event handler. I hate when my application window pops up somewhere in the corner by the will of the allmighty window manager. So I added

wx.ToolBar

Toolbar is a widget that groups the most common used commands or actions of your application. Typically save, open, cut, copy, paste, undo, redo etc. Its purpose is to save time. You need one click to do an action from the toolbar and two clicks from the menu.

wx.BoxSizer will be explained later in layout section. Toolbar widget is created in three steps.

Firstly, we create a toolbar object.

toolbar = wx.ToolBar(self, -1, style=wx.TB_HORIZONTAL | wx.NO_BORDER)

Then we add some tools to the toolbar with the AddSimpleTool() method. You don't find this method in the reference book. It is a wxPython 'extension'. This is a curse and also a blessing. It makes python programming easier. But on the other hand, these extensions are undocumented. You have to look at the wrapper code, demo example or ask on the mailing list.

The proportion parameter defines the share or ratio of available sizer space that the widget will occupy in the direction of the defined orientation. Let's assume we have three buttons with the proportions 0, 1, and 2. They are added into a horizontal wx.BoxSizer. The button with proportion 0 will not change at all when the sizer's width (horizontal size) changes (i.e. the button will always be the same width). The rest of the width of the sizer is split into 3 (2+1) shares. The button with proportion 2 will always occupy 2 of those 3 shares (its width will be 2/3 of the available width), and the button with proportion 1 will always occupy 1 of those shares.

With the flag parameter, you can further configure the behaviour of the widgets within a wx.BoxSizer. We can control the border (though "padding" would be a more accurate name than "border") between the widgets. We add some space between widgets in pixels. In order to apply border, we need to define which sides will use the border. We can choose between these flags:

wx.LEFT

wx.RIGHT

wx.BOTTOM

wx.TOP

wx.ALL

We can combine them with the | operator. e.g wx.LEFT | wx.BOTTOM. If we use wx.EXPAND flag, our widget will use all the space that is available in the direction perpendicular to the sizer's orient direction. Lastly, we can also define the alignment of our widgets. We do it with the following flags :

In our example we again have three buttons. The first one has some border around all its sides. It is the only one that changes in the horizontal dimension when the main window is resized. The second one occupies all space alloted to it in the vertical direction. The third one is aligned in the centre.

We can combine various wx.BoxSizer-s. For example, we can put several horizontal wx.BoxSizer-s into a vertical wx.BoxSizer and vice versa. This way we can make complex layouts.

We show four various border styles available in wxPython. Border is a simple window decoration.

Available Borders:

wx.SIMPLE_BORDER

wx.RAISED_BORDER

wx.SUNKEN_BORDER

wx.NO_BORDER

wx.GridSizer

wx.GridSizer lays out its children in a two-dimensional table. The width of each field is the width of the widest child. The height of each field is the height of the tallest child.

wx.GridSizer(integer rows, integer cols, integer vgap, integer hgap)

In the constructor we provide the number of rows and the number of columns of our table and the horizontal and vertical gap between the children widgets. We insert our widgets into the table with the AddMany() method. Children are inserted from left to right, top to bottom.

The formula we input is processed by the eval built-in python function.

output = eval(formula)

If we make an error in our formula, an error message is displayed. Notice how we managed to put a space between the Bck and Close buttons. We simply put an empty wx.StaticText there. Such tricks are quite common.

Figure: calculator.py

wx.GridBagSizer

The most complicated sizer in wxPython. It enables explicit positioning of the items. Items can also optionally span more than one row and/or column. wx.GridBagSizer has a simple constructor.

wx.GridBagSizer(integer vgap, integer hgap)

The vertical and the horizontal gap defines the space in pixels used between children. You add items to grid with the Add() method.

Item is a widget that you insert into the grid. pos specifies the position in the virtual grid. The topleft cell has pos of (0, 0). span is an optional spanning of the widget. e.g. span of (3, 2) spans a widget across 3 rows and 2 columns. flag and border were discussed earlier by wx.BoxSizer.

The items in the grid can change their size or keep the default size, when the window is resized. If you want your items to grow and shrink, you can use these two methods.

Cursors

A cursor is a simple graphical object. It is used to indicate position on the monitor or any other display device. It usually dynamically changes itself. Typically, when you hover a mouse pointer over a hypertext, the cursor changes to a hand.

In the next code example, we create a grid of nine wx.Panels. Each panel shows a different cursor.

The full database has currently about 630 different colour names. The list can be found in the colourdb.py file. It is also shown in the wxPython demo. In randomcolours.py script we have a single window. We change the background colour of the window to the randomly chosen colour.

Bitmaps

There are two kinds of graphics. Vector and bitmap. With vector graphics, images are created with mathematical formulas that define all the shapes of the image. Geometric objects like curves and polygons are used. A bitmap or a bit map is a collection of bits that form an image. It is a grid of individual dots stored in memory or in a file. Each dot has its own colour. When the image is displayed, the computer transfers a bit map into pixels on monitors or ink dots on printers. The quality of a bitmap is determined by the resolution and the color depth of the image. The resolution is the total number of pixels in the image. The Color depth is the amount of information in each pixel.

Events

Events are integral part of every GUI application. All GUI applications are event-driven. An application reacts to different event types which are generated during its life. Events are generated mainly by the user of an application. But they can be generated by other means as well. e.g. internet connection, window manager, timer. So when we call MainLoop() method, our application waits for events to be generated. The MainLoop() method ends when we exit the application.

Working with events is straightforward in wxPython. There are three steps:

Identify the event name: wx.EVT_SIZE, wx.EVT_CLOSE etc

Create an event handler. It is a method, that is called, when an event is generated

Bind an event to an event handler.

In wxPython we say to bind a method to an event. Sometimes a word hook is used.

You bind an event by calling the Bind() method. The method has the following parameters:

Bind(event, handler, source=None, id=wx.ID_ANY, id2=wx.ID_ANY)

event is one of EVT_* objects. It specifies the type of the event.

handler is an object to be called. In other words, it is a method, that a programmer binds to an event.

source parameter is used when we want to differentiate between the same event type from different widgets.

id parameter is used, when we have multiple buttons, menu items etc. The id is used to differentiate among them.

id2 is used when it is desirable to bind a handler to a range of ids, such as with EVT_MENU_RANGE.

Note that method Bind() is defined in class EvtHandler. It is the class, from which wx.Window inherits. wx.Window is a base class for most widgets in wxPython. There is also a reverse process. If we want to unbind a method from an event, we call the Unbind() method. It has the same paremeters as the above one.

Possible events

wx.Event

the event base class

wx.ActivateEvent

a window or application activation event

wx.CloseEvent

a close window or end session event

wx.EraseEvent

an erase background event

wx.FocusEvent

a window focus event

wx.KeyEvent

a keypress event

wx.IdleEvent

an idle event

wx.InitDialogEvent

a dialog initialisation event

wx.JoystickEvent

a joystick event

wx.MenuEvent

a menu event

wx.MouseEvent

a mouse event

wx.MoveEvent

a move event

wx.PaintEvent

a paint event

wx.QueryLayoutInfoEvent

used to query layout information

wx.SetCursorEvent

used for special cursor processing based on current mouse position

wx.SizeEvent

a size event

wx.ScrollWinEvent

a scroll event sent by a built-in Scrollbar

wx.ScrollEvent

a scroll event sent by a stand-alone scrollbar

wx.SysColourChangedEvent

a system colour change event

Examples

The following code is an example of a wx.ScrollWinEvent. This event is generated, when we click on a built in Scrollbar. Built-in Scrollbar is activated with the SetScrollbar() method call. For stand-alone Scrollbars, there is another event type, namely wx.ScrollEvent.

A paint event is generated when a window is redrawn. This happens when we resize window, maximize it. A paint event can be generated programatically as well. For example, when we call SetLabel() method to change a wxStaticText widget. Note that when we minimize a window, no paint event is generated.

Notice that you cannot resize the dialog window. The Destroy() method is necessary. It deletes the dialog from the memory. Otherwise, the script would not exit properly.

There are two types of dialogs. Modal and modeless. Modal dialog does not allow a user to work with the rest of the application until it is destroyed. Modal dialogs are created with the ShowModal() method. Dialogs are modeless when called with Show().

Custom dialogs

There are two methods that simplify the creation of dialogs. Both return a specific sizer object.

wx.StaticBox

This is a kind of a decorator widget. It is used to logically group various widgets. Note that this widget must be created before the widgets that it contains, and that those widgets should be siblings, not children, of the static box.

wx.ComboBox

wx.ComboBox is a combination of a single line text field, a button with a down arrow image and a listbox. When you press the button, a listbox appears. User can select only one option from the supplied string list.

wx.CheckBox

wx.CheckBox is a widget that has two states. On and Off. It is a box with a label. The label can be set to the right or to the left of the box. If the checkbox is checked, it is represented by a tick in a box.

wx.StatusBar

As its name indicates, thewx.StatusBar widget is used to display application status information. It can be divided into several parts to show different kind of information. We can insert other widgets into the wx.StatusBar. It can be used as an alternative to dialogs, since dialogs are ofted abused and are disliked by most users. We can create a

wx.StatusBar in two ways. We can manually create our own wx.StatusBar and call SetStatusBar() method or we can simply call a CreateStatusBar() method. The latter method creates a default wx.StatusBar for us. In our first example, we have a

wx.Frame widget and five other widgets. If we hover a mouse pointer over a widget, its description is shown on the wx.StatusBar

wx.RadioButton

wx.RadioButton is a widget that allows the user to select a single exclusive choice from a group of options. A group of radio buttons is defined by having the first RadioButton in the group contain the wx.RB_GROUP style. All other RadioButtons defined after the first RadioButton with this style flag is set will be added to the function group of the first RadioButton. Declaring another RadioButton with the wx.RB_GROUP flag will start a new radio button group.

wx.Slider

wx.Slider is a widget that has a simple handle. This handle can be pulled back and forth. This way we are choosing a value for a specific task. Say we want to input into our application the age of a customer. For this purpose, wx.Slider might be a good choice.

wx.Slider styles

wxSL_HORIZONTAL

wxSL_VERTICAL

wxSL_AUTOTICKS

wxSL_LABELS

wxSL_LEFT

wxSL_RIGHT

wxSL_TOP

wxSL_BOTTOM

wxSL_INVERSE

wx.Slider methods

integer GetValue()

get the current slider value

SetValue(integer value)

set the slider position

SetRange(integer min, integer max)

set the minimum and maximum slider value

integer GetMin()

get the minimum slider value

integer GetMax()

get the maximum slider value

SetMin(integer min)

set the minimum slider value

integer SetMax(integer max)

set the maximum slider value

SetLineSize(integer size)

set the line size for the slider

SetPageSize(integer pageSize)

set the page size for the slider

pageSize - the number of steps the slider moves when the user pages up or down.

In this example we have a slider and two buttons. Slider initial position is set to 200. The min value is 150, max value is 500. When you click adjust button, the frame size is changed. The height is set to value chosen by slider, the width is set to 2 x value.

Figure: slider.py

wx.ListBox

wx.Listbox is a widget that consists of a scrolling box and a list of items. User can select one or more items from that list. It depends on whether it is created as a single or multiple selection box. Selected items are marked.

listbox.py example consists of four different widgets.wx.Listbox, wx.TextCtrl, wx.StaticText and wx.Button. Widgets are organized with wx.BoxSizer-s. wx.Listbox has a list of six different world times. These abbreviations are explained in the wx.TextCtrl. Current time is displayed in the wx.StaticText widget. wx.Timer widget is used to update the time every 100 miliseconds.

Figure: listbox.py

wx.SpinCtrl

This widget lets you increment and decrement a value. It has two up and down arrow buttons for this purpose. User can enter a value into a box or increment/decrement it by these two arrows.

spinctrl.py is a dialog-based script. Our main class inherits fromwx.Dialog instead of wx.Frame. The main difference is that we cannot resize the window and we call Destroy() method instead of Close(), when we quit the application. spinctrl.py script converts Fahrenheit temperature to Celsius. This example is very popular and can be found in most programming primer books.

Figure spinctrl.py

wx.ListCtrl

wx.ListCtrl creates lists in the following formats:

report view

list view

icon view

In our example, we key in the states and their capitals and add them into the list widget. We use report view.

wx.SplitterWindow

This widget enables to split the main area of an application into parts. The user can dynamically resize those parts with the mouse pointer. Such a solution can be seen in mail clients (evolution) or in burning software (k3b). You can split an area vertically or horizontally.

wx.ScrolledWindow

This is one of the container widgets. It can be useful, when we have a larger area than a window can display. In our example, we demonstrate such a case. We place a large image into our window. When the window is smaller than our image, Scrollbars are displayed automatically.

In our example, we have registered a mouse gesture for a panel. Mouse gesture is triggered, when a left button is pressed and we go down and right with a cursor. As in letter 'L'. Our mouse gesture will close the application. If we want to use mouse gestures, we have to create a

MouseGesture object. The first parameter is a window, where the mouse gesture is registered. Second parameter defines a way to register a gesture. True is for automatic, False for manual. Manual is not fully implemented and we are happy with the automatic way. Last parameter defines a mouse button, which will be pressed when triggering gestures. The button can be later changed with the SetMouseButton() method.

mg = gest.MouseGestures(panel, True, wx.MOUSE_BTN_LEFT)

Our gestures will be painted as red lines. They will be 2 pixels wide.

mg.SetGesturePen(wx.Colour(255, 0, 0), 2)

We set this gesture visible with theSetGesturesVisible() method.

mg.SetGesturesVisible(True)

We register a mouse gesture with theAddGesture() method. The first parameter is the gesture. Second parameter is the method triggered by the gesture.