Differences between revisions 306 and 307
Revision 306 as of 2010-07-12 18:21:39
Size: 199503
Editor: 143-189-179-94
Comment:
Revision 307 as of 2010-07-12 18:29:08
Size: 199451
Editor: c-98-246-90-205
Comment: remove spam
Deletions are marked like this. Additions are marked like this.
Line 5368: Line 5368:
Kika is a gript that connects to an ftp site. If a login is successfull, Kika shows a connected icon on the statusbar. Otherwise, a disconnected icon is displayed. We use an ftplib module from the python standard [http://customwritingservices.org/ writing service] library. If you do not have an ftp account, you can try to login to some anonymous ftp sites. Kika is a gript that connects to an ftp site. If a login is successfull, Kika shows a connected icon on the statusbar. Otherwise, a disconnected icon is displayed. We use an ftplib module from the python standard library. If you do not have an ftp account, you can try to login to some anonymous ftp sites.

The wxPython Linux Tutorial

Table of Contents:

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.

  • mailing list
  • reference book
  • source code of wxPython applications
  • /home/vronskij/bin/wxPython/usr/lib/python2.4/site-packages/wx-2.6-gtk2-unicode/wx - the ultimate resource, on my Linux box

There are three decent toolkits for the python programming language:

  • wxPython

  • PyQt

  • PyGTK

Note that this tutorial is done on Linux. Some scripts do not work correctly on windows.

Icons used in this tutorial: icons.tgz Images used in this tutorial: images.tgz

jan bodnar 2005 - 2007

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.

  • wx.MenuBar

  • wx.ToolBar

  • wx.StatusBar

First Steps

We start with a simple example.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # simple.py
   4 
   5 import wx
   6 
   7 app = wx.App()
   8 
   9 frame = wx.Frame(None, -1, 'simple.py')
  10 frame.Show()
  11 
  12 app.MainLoop()

In every wxPython application, we must import the wx library.

import wx

An application object is created by initiating class wx.App.

app = wx.App()

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.

simple.png

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 it's 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.

  • Move(wx.Point pos) - Moves the window to the given position.

  • SetCursor(wx.StockCursor id) - Sets the window's cursor.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # simple2.py
   4 
   5 import wx
   6 
   7 app = wx.App()
   8 
   9 frame = wx.Frame(None, -1, '')
  10 frame.SetToolTip(wx.ToolTip('This is a frame'))
  11 frame.SetCursor(wx.StockCursor(wx.CURSOR_MAGNIFIER))
  12 frame.SetPosition(wx.Point(0,0))
  13 frame.SetSize(wx.Size(300,250))
  14 frame.SetTitle('simple2.py')
  15 frame.Show()
  16 
  17 app.MainLoop()

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:

wx.Frame(wx.Window parent, id, string title,
         wx.Point pos = wx.DefaultPosition, wx.Size size = wx.DefaultSize,
         style = wx.DEFAULT_FRAME_STYLE, string name = 'frame')

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 it's 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, it's identifier is 100, the title is 'Title', the position is (100,50) and the size is (100,100).

frame = wx.Frame(None, 100, 'Title', wx.Point(100,50), wx.Size(100,100))

Here we have omitted the pos parameter. So we must provide explicitly the size parameter.

frame = wx.Frame(None, 100, 'Title', size = wx.Size(100,100))

In the following example we will use other useful features.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # icon.py
   4 
   5 import wx
   6 
   7 def main():
   8     app = wx.App()
   9 
  10     frame = wx.Frame(None, title='Icon', pos=(350,300))
  11     frame.SetIcon(wx.Icon('tipi.ico', wx.BITMAP_TYPE_ICO))
  12     frame.Center()
  13     frame.Show()
  14     app.MainLoop()
  15 
  16 if __name__ == '__main__':
  17     main()

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.

icon.png

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.

First thing to do is to create a menubar.

menubar = wx.MenuBar()

Then we create our menus.

file = wx.Menu()
edit = wx.Menu()
help = wx.Menu()

Then we add some items into the menu. This can be done in two ways.

file.Append(101, '&Open', 'Open a new document')
file.Append(102, '&Save', 'Save the document')

We can separate logical sections in menus with a horizontal line.

file.AppendSeparator()

If you want to have some icons in your menus, you need to create MenuItem objects manually.

quit = wx.MenuItem(file, 105, '&Quit\tCtrl+Q', 'Quit the Application')
quit.SetBitmap(wx.Image('stock_exit-16.png',wx.BITMAP_TYPE_PNG).ConvertToBitmap())
file.AppendItem(quit)

wxPython toolkit can only put bitmaps into menus. Therefore we need to convert our PNG files into bitmaps.

Menus are then added into the menubar.

menubar.Append(file, '&File')
menubar.Append(edit, '&Edit')
menubar.Append(help, '&Help')

Finally we set up our menubar in our application class.

self.SetMenuBar(menubar)

Let's sum it up in a small script.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # menu1.py
   4 
   5 import wx
   6 
   7 class MyMenu(wx.Frame):
   8     def __init__(self, parent, id, title):
   9         wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(200, 150))
  10 
  11         menubar = wx.MenuBar()
  12         file = wx.Menu()
  13         edit = wx.Menu()
  14         help = wx.Menu()
  15         file.Append(101, '&Open', 'Open a new document')
  16         file.Append(102, '&Save', 'Save the document')
  17         file.AppendSeparator()
  18         quit = wx.MenuItem(file, 105, '&Quit\tCtrl+Q', 'Quit the Application')
  19         quit.SetBitmap(wx.Image('stock_exit-16.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap())
  20         file.AppendItem(quit)
  21 
  22         menubar.Append(file, '&File')
  23         menubar.Append(edit, '&Edit')
  24         menubar.Append(help, '&Help')
  25         self.SetMenuBar(menubar)
  26         self.CreateStatusBar()
  27 
  28 class MyApp(wx.App):
  29     def OnInit(self):
  30         frame = MyMenu(None, -1, 'menu1.py')
  31         frame.Show(True)
  32         return True
  33 
  34 app = MyApp(0)
  35 app.MainLoop()

So far we have seen the default, normal menu items. Here we see, how we can explicitly define check items, normal items or radio items.

edit.Append(201, 'check item1', '', wx.ITEM_CHECK)
edit.Append(202, 'check item2', '', kind=wx.ITEM_CHECK)

or

quit = wxMenuItem(file, 105, '&Quit\tCtrl+Q', 'Quit the Application', wx.ITEM_NORMAL)

The parameter is called kind.

Possible wx.ItemKind-s

  • wx.ITEM_NORMAL - default item
  • wx.ITEM_CHECK - check item
  • wx.ITEM_RADIO - radio item

If you want to create a submenu, you create a menu first.

submenu = wx.Menu()

Then append some menu items into this submenu.

submenu.Append(301, 'radio item1', kind=wx.ITEM_RADIO)
submenu.Append(302, 'radio item2', kind=wx.ITEM_RADIO)
submenu.Append(302, 'radio item3', kind=wx.ITEM_RADIO)

You finish with adding a submenu into a menu object.

edit.AppendMenu(203, 'submenu', submenu)

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

self.Centre()

so that the window pops up in the center of the screen.

menu1.png

Figure: menu1.py

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # menu2.py
   4 
   5 import wx
   6 
   7 class MyMenu(wx.Frame):
   8     def __init__(self, parent, id, title):
   9         wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(380, 250))
  10 
  11         menubar = wx.MenuBar()
  12         file = wx.Menu()
  13         edit = wx.Menu()
  14         help = wx.Menu()
  15         file.Append(101, '&Open', 'Open a new document')
  16         file.Append(102, '&Save', 'Save the document')
  17         file.AppendSeparator()
  18         quit = wx.MenuItem(file, 105, '&Quit\tCtrl+Q', 'Quit the Application')
  19         quit.SetBitmap(wx.Image('stock_exit-16.png',wx.BITMAP_TYPE_PNG).ConvertToBitmap())
  20         file.AppendItem(quit)
  21         edit.Append(201, 'check item1', '', wx.ITEM_CHECK)
  22         edit.Append(202, 'check item2', kind=wx.ITEM_CHECK)
  23         submenu = wx.Menu()
  24         submenu.Append(301, 'radio item1', kind=wx.ITEM_RADIO)
  25         submenu.Append(302, 'radio item2', kind=wx.ITEM_RADIO)
  26         submenu.Append(303, 'radio item3', kind=wx.ITEM_RADIO)
  27         edit.AppendMenu(203, 'submenu', submenu)
  28         menubar.Append(file, '&File')
  29         menubar.Append(edit, '&Edit')
  30         menubar.Append(help, '&Help')
  31         self.SetMenuBar(menubar)
  32         self.Centre()
  33         self.Bind(wx.EVT_MENU, self.OnQuit, id=105)
  34 
  35     def OnQuit(self, event):
  36         self.Close()
  37 
  38 class MyApp(wx.App):
  39     def OnInit(self):
  40         frame = MyMenu(None, -1, 'menu2.py')
  41         frame.Show(True)
  42         return True
  43 
  44 app = MyApp(0)
  45 app.MainLoop()

menu2.png

Figure: menu2.py

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. It's purpose is to save time. You need one click to do an action from the toolbar and two clicks from the menu.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # toolbar.py
   4 
   5 import wx
   6 
   7 class MyToolBar(wx.Frame):
   8     def __init__(self, parent, id, title):
   9         wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(350, 250))
  10 
  11         vbox = wx.BoxSizer(wx.VERTICAL)
  12         toolbar = wx.ToolBar(self, -1, style=wx.TB_HORIZONTAL | wx.NO_BORDER)
  13         toolbar.AddSimpleTool(1, wx.Image('stock_new.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'New', '')
  14         toolbar.AddSimpleTool(2, wx.Image('stock_open.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'Open', '')
  15         toolbar.AddSimpleTool(3, wx.Image('stock_save.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'Save', '')
  16         toolbar.AddSeparator()
  17         toolbar.AddSimpleTool(4, wx.Image('stock_exit.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'Exit', '')
  18         toolbar.Realize()
  19         vbox.Add(toolbar, 0, border=5)
  20         self.SetSizer(vbox)
  21         self.statusbar = self.CreateStatusBar()
  22         self.Centre()
  23 
  24         self.Bind(wx.EVT_TOOL, self.OnNew, id=1)
  25         self.Bind(wx.EVT_TOOL, self.OnOpen, id=2)
  26         self.Bind(wx.EVT_TOOL, self.OnSave, id=3)
  27         self.Bind(wx.EVT_TOOL, self.OnExit, id=4)
  28 
  29     def OnNew(self, event):
  30         self.statusbar.SetStatusText('New Command')
  31 
  32     def OnOpen(self, event):
  33         self.statusbar.SetStatusText('Open Command')
  34 
  35     def OnSave(self, event):
  36         self.statusbar.SetStatusText('Save Command')
  37 
  38     def OnExit(self, event):
  39         self.Close()
  40 
  41 class MyApp(wx.App):
  42     def OnInit(self):
  43         frame = MyToolBar(None, -1, 'toolbar.py')
  44         frame.Show(True)
  45         return True
  46 
  47 app = MyApp(0)
  48 app.MainLoop()

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.

toolbar.AddSimpleTool(1, wx.Image('stock_new.png',  wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'New', '')

In the end, we call the Realize() method. This method shows or renders the toolbar widget.

toolbar.Realize()

The toolbar widget has several event handlers. When you click on a toolbar icon a wx.EVT_COMMAND_TOOL_CLICKED event is generated. We bind this event to a specified method with the wx.EVT_TOOL handler.

In order to show some meaningful output to our events, we have set up a statusbar.

self.statusbar = self.CreateStatusBar()

This is yet another wxPython extension. So when we click on a toolbar button, a message is displayed on the statusbar. This is done with the SetStatusText() method.

toolbar.png

Figure: toolbar.py

Layout Management

There are basically two methods for layout of our widgets. The first method is manual. We place widgets by specifying the position in the constructor of the widget.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # layout.py
   4 
   5 import wx
   6 
   7 class MyFrame(wx.Frame):
   8     def __init__(self, parent, id, title):
   9         wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(250, 50))
  10 
  11         panel = wx.Panel(self, -1)
  12         wx.Button(panel, -1, "Button1", (0,0))
  13         wx.Button(panel, -1, "Button2", (80,0))
  14         wx.Button(panel, -1, "Button3", (160,0))
  15 
  16 class MyApp(wx.App):
  17     def OnInit(self):
  18         frame = MyFrame(None, -1, 'layout.py')
  19         frame.Show(True)
  20         frame.Centre()
  21         return True
  22 
  23 app = MyApp(0)
  24 app.MainLoop()

When the window is resized, the size and the position of buttons do not change. This is one of the main features of the manual positioning of the widgets.

layout.png

Figure: layout.py

The second method is to use layout managers. This method is prevalent in real programs. Basically you use sizers. We will discuss

  • wx.BoxSizer

  • wx.StaticBoxSizer

  • wx.GridSizer

  • wx.GridBagSizer

wx.BoxSizer

Let's make a program in which three buttons will occupy one row placed at the top of the window. These buttons will resize when the window is resized.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # wxboxsizer.py
   4 
   5 import wx
   6 
   7 class MyFrame(wx.Frame):
   8     def __init__(self, parent, id, title):
   9         wx.Frame.__init__(self, parent, id, title, (-1, -1), wx.Size(250, 50))
  10         panel = wx.Panel(self, -1)
  11         box = wx.BoxSizer(wx.HORIZONTAL)
  12         box.Add(wx.Button(panel, -1, 'Button1'), 1 )
  13         box.Add(wx.Button(panel, -1, 'Button2'), 1 )
  14         box.Add(wx.Button(panel, -1, 'Button3'), 1 )
  15         panel.SetSizer(box)
  16         self.Centre()
  17 
  18 class MyApp(wx.App):
  19      def OnInit(self):
  20          frame = MyFrame(None, -1, 'wxboxsizer.py')
  21          frame.Show(True)
  22          return True
  23 
  24 app = MyApp(0)
  25 app.MainLoop()

We can place widgets vertically or horizontally.

box = wx.BoxSizer(integer orient)

where orientation can be wx.VERTICAL or wx.HORIZONTAL. Adding widgets into the wx.BoxSizer is done via the Add() method. In order to understand it, we need to look at its parameters.

Add(wx.Window window, integer proportion=0, integer flag = 0, integer border = 0)

wxboxsizer.png

Figure: wxboxsizer.py

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 :

  • wx.ALIGN_LEFT
  • wx.ALIGN_RIGHT
  • wx.ALIGN_TOP
  • wx.ALIGN_BOTTOM
  • wx.ALIGN_CENTER_VERTICAL
  • wx.ALIGN_CENTER_HORIZONTAL
  • wx.ALIGN_CENTER

An example:

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # layout3.py
   4 
   5 import wx
   6 
   7 class MyFrame(wx.Frame):
   8     def __init__(self, parent, id, title):
   9         wx.Frame.__init__(self, parent, id, title, (-1, -1), wx.Size(450, 300))
  10 
  11         panel = wx.Panel(self, -1)
  12         box = wx.BoxSizer(wx.HORIZONTAL)
  13         box.Add(wx.Button(panel, -1, 'Button1'), 1, wx.ALL, 5)
  14         box.Add(wx.Button(panel, -1, 'Button2'), 0, wx.EXPAND)
  15         box.Add(wx.Button(panel, -1, 'Button3'), 0, wx.ALIGN_CENTER)
  16         panel.SetSizer(box)
  17         self.Centre()
  18 
  19 class MyApp(wx.App):
  20     def OnInit(self):
  21         frame = MyFrame(None, -1, 'layout3.py')
  22         frame.Show(True)
  23         return True
  24 
  25 app = MyApp(0)
  26 app.MainLoop()

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.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # borders.py
   4 
   5 import wx
   6 
   7 class MyFrame(wx.Frame):
   8     def __init__(self, parent, id, title):
   9 
  10         wx.Frame.__init__(self, parent, id, title)
  11         hbox = wx.BoxSizer(wx.HORIZONTAL)
  12         pnl1 = wx.Panel(self, -1, style=wx.SIMPLE_BORDER)
  13         pnl2 = wx.Panel(self, -1, style=wx.RAISED_BORDER)
  14         pnl3 = wx.Panel(self, -1, style=wx.SUNKEN_BORDER)
  15         pnl4 = wx.Panel(self, -1, style=wx.NO_BORDER)
  16 
  17         hbox.Add(pnl1, 1, wx.EXPAND | wx.ALL, 3)
  18         hbox.Add(pnl2, 1, wx.EXPAND | wx.ALL, 3)
  19         hbox.Add(pnl3, 1, wx.EXPAND | wx.ALL, 3)
  20         hbox.Add(pnl4, 1, wx.EXPAND | wx.ALL, 3)
  21 
  22         self.SetSize((400, 120))
  23         self.SetSizer(hbox)
  24         self.Centre()
  25 
  26 class MyApp(wx.App):
  27     def OnInit(self):
  28         frame = MyFrame(None, -1, 'borders.py')
  29         frame.Show(True)
  30         return True
  31 
  32 app = MyApp(0)
  33 app.MainLoop()

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

borders.png

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.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # calculator.py
   4 
   5 import wx
   6 
   7 class MyFrame(wx.Frame):
   8     def __init__(self, parent, id, title):
   9 
  10         wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(300, 250))
  11         self.formula = False
  12         menubar = wx.MenuBar()
  13         file = wx.Menu()
  14         file.Append(22, '&Quit', 'Exit Calculator')
  15         menubar.Append(file, '&File')
  16         self.SetMenuBar(menubar)
  17         wx.EVT_MENU(self, 22, self.OnClose)
  18         sizer = wx.BoxSizer(wx.VERTICAL)
  19         self.display = wx.TextCtrl(self, -1, '',  style=wx.TE_RIGHT)
  20         sizer.Add(self.display, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 4)
  21 
  22         gs = wx.GridSizer(4, 4, 3, 3)
  23         gs.AddMany([(wx.Button(self, 20, 'Cls'), 0, wx.EXPAND),
  24                         (wx.Button(self, 21, 'Bck'), 0, wx.EXPAND),
  25                         (wx.StaticText(self, -1, ''), 0, wx.EXPAND),
  26                         (wx.Button(self, 22, 'Close'), 0, wx.EXPAND),
  27                         (wx.Button(self, 1, '7'), 0, wx.EXPAND),
  28                         (wx.Button(self, 2, '8'), 0, wx.EXPAND),
  29                         (wx.Button(self, 3, '9'), 0, wx.EXPAND),
  30                         (wx.Button(self, 4, '/'), 0, wx.EXPAND),
  31                         (wx.Button(self, 5, '4'), 0, wx.EXPAND),
  32                         (wx.Button(self, 6, '5'), 0, wx.EXPAND),
  33                         (wx.Button(self, 7, '6'), 0, wx.EXPAND),
  34                         (wx.Button(self, 8, '*'), 0, wx.EXPAND),
  35                         (wx.Button(self, 9, '1'), 0, wx.EXPAND),
  36                         (wx.Button(self, 10, '2'), 0, wx.EXPAND),
  37                         (wx.Button(self, 11, '3'), 0, wx.EXPAND),
  38                         (wx.Button(self, 12, '-'), 0, wx.EXPAND),
  39                         (wx.Button(self, 13, '0'), 0, wx.EXPAND),
  40                         (wx.Button(self, 14, '.'), 0, wx.EXPAND),
  41                         (wx.Button(self, 15, '='), 0, wx.EXPAND),
  42                         (wx.Button(self, 16, '+'), 0, wx.EXPAND) ])
  43 
  44         sizer.Add(gs, 1, wx.EXPAND)
  45 
  46         self.SetSizer(sizer)
  47         self.Centre()
  48 
  49         self.Bind(wx.EVT_BUTTON, self.OnClear, id=20)
  50         self.Bind(wx.EVT_BUTTON, self.OnBackspace, id=21)
  51         self.Bind(wx.EVT_BUTTON, self.OnClose, id=22)
  52         self.Bind(wx.EVT_BUTTON, self.OnSeven, id=1)
  53         self.Bind(wx.EVT_BUTTON, self.OnEight, id=2)
  54         self.Bind(wx.EVT_BUTTON, self.OnNine, id=3)
  55         self.Bind(wx.EVT_BUTTON, self.OnDivide, id=4)
  56         self.Bind(wx.EVT_BUTTON, self.OnFour, id=5)
  57         self.Bind(wx.EVT_BUTTON, self.OnFive, id=6)
  58         self.Bind(wx.EVT_BUTTON, self.OnSix, id=7)
  59         self.Bind(wx.EVT_BUTTON, self.OnMultiply, id=8)
  60         self.Bind(wx.EVT_BUTTON, self.OnOne, id=9)
  61         self.Bind(wx.EVT_BUTTON, self.OnTwo, id=10)
  62         self.Bind(wx.EVT_BUTTON, self.OnThree, id=11)
  63         self.Bind(wx.EVT_BUTTON, self.OnMinus, id=12)
  64         self.Bind(wx.EVT_BUTTON, self.OnZero, id=13)
  65         self.Bind(wx.EVT_BUTTON, self.OnDot, id=14)
  66         self.Bind(wx.EVT_BUTTON, self.OnEqual, id=15)
  67         self.Bind(wx.EVT_BUTTON, self.OnPlus, id=16)
  68 
  69     def OnClear(self, event):
  70         self.display.Clear()
  71 
  72     def OnBackspace(self, event):
  73         formula = self.display.GetValue()
  74         self.display.Clear()
  75         self.display.SetValue(formula[:-1])
  76 
  77     def OnClose(self, event):
  78         self.Close()
  79 
  80     def OnDivide(self, event):
  81         if self.formula:
  82             return
  83         self.display.AppendText('/')
  84 
  85     def OnMultiply(self, event):
  86         if self.formula:
  87             return
  88         self.display.AppendText('*')
  89 
  90     def OnMinus(self, event):
  91         if self.formula:
  92             return
  93         self.display.AppendText('-')
  94 
  95     def OnPlus(self, event):
  96         if self.formula:
  97             return
  98         self.display.AppendText('+')
  99 
 100     def OnDot(self, event):
 101         if self.formula:
 102             return
 103         self.display.AppendText('.')
 104 
 105     def OnEqual(self, event):
 106         if self.formula:
 107             return
 108         formula = self.display.GetValue()
 109         self.formula = False
 110         try:
 111             self.display.Clear()
 112             output = eval(formula)
 113             self.display.AppendText(str(output))
 114         except StandardError:
 115             self.display.AppendText("Error")
 116 
 117     def OnZero(self, event):
 118         if self.formula:
 119             self.display.Clear()
 120             self.formula = False
 121         self.display.AppendText('0')
 122 
 123     def OnOne(self, event):
 124         if self.formula:
 125             self.display.Clear()
 126             self.formula = False
 127         self.display.AppendText('1')
 128 
 129     def OnTwo(self, event):
 130         if self.formula:
 131             self.display.Clear()
 132             self.formula = False
 133         self.display.AppendText('2')
 134 
 135     def OnThree(self, event):
 136         if self.formula:
 137             self.display.Clear()
 138             self.formula = False
 139         self.display.AppendText('3')
 140 
 141     def OnFour(self, event):
 142         if self.formula:
 143             self.display.Clear()
 144             self.formula = False
 145         self.display.AppendText('4')
 146 
 147     def OnFive(self, event):
 148         if self.formula:
 149             self.display.Clear()
 150             self.formula = False
 151         self.display.AppendText('5')
 152 
 153     def OnSix(self, event):
 154         if self.formula:
 155             self.display.Clear()
 156             self.formula = False
 157         self.display.AppendText('6')
 158 
 159     def OnSeven(self, event):
 160         if self.formula:
 161             self.display.Clear()
 162             self.formula = False
 163         self.display.AppendText('7')
 164 
 165     def OnEight(self, event):
 166         if self.formula:
 167             self.display.Clear()
 168             self.formula = False
 169         self.display.AppendText('8')
 170 
 171     def OnNine(self, event):
 172         if self.formula:
 173             self.display.Clear()
 174             self.formula = False
 175         self.display.AppendText('9')
 176 
 177 class MyApp(wx.App):
 178     def OnInit(self):
 179         frame = MyFrame(None, -1, 'calculator.py')
 180         frame.Show(True)
 181         self.SetTopWindow(frame)
 182         return True
 183 
 184 app = MyApp(0)
 185 app.MainLoop()

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.

calculator.png

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.

Add(self, item, tuple pos, tuple span=wx.DefaultSpan, integer flag=0, integer border=0, userData=None)

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.

AddGrowableRow(integer row)
AddGrowableCol(integer col)

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # wxgridbagsizer.py
   4 
   5 import wx
   6 
   7 class MyFrame(wx.Frame):
   8     def __init__(self, parent, id, title):
   9         wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition)
  10 
  11         sizer = wx.GridBagSizer(9, 9)
  12         sizer.Add(wx.Button(self,-1, "Button"), (0, 0), wx.DefaultSpan,  wx.ALL, 5)
  13         sizer.Add(wx.Button(self,-1, "Button"), (1, 1), (1,7), wx.EXPAND)
  14         sizer.Add(wx.Button(self,-1, "Button"), (6, 6), (3,3), wx.EXPAND)
  15         sizer.Add(wx.Button(self,-1, "Button"), (3, 0), (1,1), wx.ALIGN_CENTER)
  16         sizer.Add(wx.Button(self,-1, "Button"), (4, 0), (1,1), wx.ALIGN_LEFT)
  17         sizer.Add(wx.Button(self,-1, "Button"), (5, 0), (1,1), wx.ALIGN_RIGHT)
  18         sizer.AddGrowableRow(6)
  19         sizer.AddGrowableCol(6)
  20 
  21         self.SetSizerAndFit(sizer)
  22         self.Centre()
  23 
  24 class MyApp(wx.App):
  25     def OnInit(self):
  26         frame = MyFrame(None, -1, "wxgridbagsizer.py")
  27         frame.Show(True)
  28         self.SetTopWindow(frame)
  29         return True
  30 
  31 app = MyApp(0)
  32 app.MainLoop()

If you want your item to span more than one cell, you must provide wx.EXPAND flag.

self.SetSizerAndFit(sizer)

This method is same as SetSizer() except that it also sends size hints to the window. All buttons are displayed on the window.

Basic Objects

wxPython is a collection of various objects. We can divide them into two groups.

  • Visual objects
  • Non-visual objects

Examples of visual objects are: widgets, fonts, colours or cursors. Non-visual objects: sizers, timers or events.

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.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # cursors.py
   4 
   5 import wx
   6 
   7 class Cursors(wx.Frame):
   8     def __init__(self, parent, id, title):
   9         wx.Frame.__init__(self, parent, id, title)
  10 
  11         vbox = wx.BoxSizer(wx.VERTICAL)
  12         sizer = wx.GridSizer(3, 3, 2, 2)
  13 
  14         cursors = [ wx.CURSOR_ARROW, wx.CURSOR_HAND, wx.CURSOR_WATCH, wx.CURSOR_SPRAYCAN, wx.CURSOR_PENCIL,
  15                     wx.CURSOR_CROSS, wx.CURSOR_QUESTION_ARROW, wx.CURSOR_POINT_LEFT, wx.CURSOR_SIZING]
  16 
  17         for i in cursors:
  18             panel = wx.Panel(self, -1, style=wx.SUNKEN_BORDER)
  19             panel.SetCursor(wx.StockCursor(i))
  20             sizer.Add(panel, flag=wx.EXPAND)
  21 
  22         vbox.Add(sizer, 1, wx.EXPAND | wx.TOP, 5)
  23         self.SetSizer(vbox)
  24 
  25         self.Centre()
  26         self.Show()
  27 
  28 
  29 app = wx.App(0)
  30 Cursors(None, -1, 'Cursors.py')
  31 app.MainLoop()

Various predefined cursors: Listed below.

Fonts

We create different kinds of fonts with the wx.Font object. It has the following constructor:

wx.Font(integer pointSize, wx.FontFamily family, integer style, integer weight,
        bool underline = false, string faceName = '',
        wx.FontEncoding encoding = wx.FONTENCODING_DEFAULT)

The specified parameters can have the following options:

family:

  • wx.DEFAULT
  • wx.DECORATIVE
  • wx.ROMAN
  • wx.SWISS
  • wx.SCRIPT
  • wx.MODERN

style:

  • wx.NORMAL
  • wx.SLANT
  • wx.ITALIC

weight:

  • wx.NORMAL
  • wx.LIGHT
  • wx.BOLD

fonts.py script shows three different fonts.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # fonts.py
   4 
   5 import wx
   6 
   7 class MyFrame(wx.Frame):
   8     def __init__(self, parent, id, title):
   9         wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(325, 320))
  10 
  11         panel = wx.Panel(self, -1)
  12 
  13         text1 = "Now listen to me mama\nMama mama\nYou're taking away my last chance\nDon't take it away"
  14 
  15         text2 = '''You won't cry for my absence, I know -
  16 You forgot me long ago.
  17 Am I that unimportant...?
  18 Am I so insignificant...?
  19 Isn't something missing?
  20 Isn't someone missing me?'''
  21 
  22         text3 = '''But if I had one wish fulfilled tonight
  23 I'd ask for the sun to never rise
  24 If God passed a mic to me to speak
  25 I'd say stay in bed, world
  26 Sleep in peace'''
  27 
  28         font1 = wx.Font(10, wx.NORMAL, wx.ITALIC, wx.NORMAL)
  29         font2 = wx.Font(10, wx.ROMAN, wx.NORMAL, wx.NORMAL)
  30         font3 = wx.Font(10, wx.MODERN, wx.NORMAL, wx.BOLD)
  31         lyrics1 = wx.StaticText(panel, -1, text1,(30,15), style=wx.ALIGN_CENTRE)
  32         lyrics1.SetFont(font1)
  33         lyrics2 = wx.StaticText(panel, -1, text2,(30,100), style=wx.ALIGN_CENTRE)
  34         lyrics2.SetFont(font2)
  35         lyrics3 = wx.StaticText(panel, -1, text3,(5,220), style=wx.ALIGN_CENTRE)
  36         lyrics3.SetFont(font3)
  37         self.Center()
  38 
  39 class MyApp(wx.App):
  40     def OnInit(self):
  41         frame = MyFrame(None, -1, 'fonts.py')
  42         frame.Show(True)
  43         self.SetTopWindow(frame)
  44         return True
  45 
  46 app = MyApp(0)
  47 app.MainLoop()

fonts.png

Figure: fonts.py

Colours

A colour is an object representing a combination of Red, Green, and Blue (RGB) intensity values. Valid RGB values are in the range 0 to 255.

There are three ways for setting colours. We can create a wx.Colour object, use a predefined colour name or use hex value string.

SetBackgroundColour(wx.Colour(0,0,255))
SetBackgroundColour('BLUE')
SetBackgroundColour('#0000FF')

Predefined colour names in wxPython:

  • wx.BLACK
  • wx.WHITE
  • wx.RED
  • wx.BLUE
  • wx.GREEN
  • wx.CYAN
  • wx.LIGHT_GREY

Standard colour database:

Listed below.

colours.py script shows eight different colours. wxBlack is simple. sea green is poetic and #0000FF technical. It is up to the developer, what to choose.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # colours.py
   4 
   5 import wx
   6 
   7 
   8 class Colours(wx.Dialog):
   9     def __init__(self, parent, id, title):
  10 
  11         wx.Dialog.__init__(self, parent, id, title, size=(300, 300))
  12         vbox = wx.BoxSizer(wx.VERTICAL)
  13         self.pnl1 = wx.Panel(self, -1)
  14         self.pnl2 = wx.Panel(self, -1)
  15         self.pnl3 = wx.Panel(self, -1)
  16         self.pnl4 = wx.Panel(self, -1)
  17         self.pnl5 = wx.Panel(self, -1)
  18         self.pnl6 = wx.Panel(self, -1)
  19         self.pnl7 = wx.Panel(self, -1)
  20         self.pnl8 = wx.Panel(self, -1)
  21 
  22         gs = wx.GridSizer(4,2,3,3)
  23         gs.AddMany([ (self.pnl1, 0 ,wx.EXPAND),
  24             (self.pnl2, 0, wx.EXPAND),
  25             (self.pnl3, 0, wx.EXPAND),
  26             (self.pnl4, 0, wx.EXPAND),
  27             (self.pnl5, 0, wx.EXPAND),
  28             (self.pnl6, 0, wx.EXPAND),
  29             (self.pnl7, 0, wx.EXPAND),
  30             (self.pnl8, 0, wx.EXPAND) ])
  31 
  32         vbox.Add(gs, 1, wx.EXPAND | wx.TOP, 5)
  33         self.SetSizer(vbox)
  34         self.SetColors()
  35         self.Centre()
  36         self.ShowModal()
  37         self.Destroy()
  38 
  39     def SetColors(self):
  40         self.pnl1.SetBackgroundColour(wx.BLACK)
  41         self.pnl2.SetBackgroundColour(wx.Colour(139,105,20))
  42         self.pnl3.SetBackgroundColour(wx.RED)
  43         self.pnl4.SetBackgroundColour('#0000FF')
  44         self.pnl5.SetBackgroundColour('sea green')
  45         self.pnl6.SetBackgroundColour('midnight blue')
  46         self.pnl7.SetBackgroundColour(wx.LIGHT_GREY)
  47         self.pnl8.SetBackgroundColour('plum')
  48 
  49 app = wx.App(0)
  50 Colours(None, -1, 'colours.py')
  51 app.MainLoop()

colours.png

Figure: colours.py

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.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # randomcolours.py
   4 
   5 import wx
   6 
   7 from random import randrange
   8 from wx.lib.colourdb import *
   9 
  10 class MyFrame(wx.Frame):
  11     def __init__(self, parent, id, title):
  12         wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(400, 350))
  13 
  14         self.panel = wx.Panel(self, -1)
  15         self.colors = getColourList()
  16         self.timer = wx.Timer(self)
  17         self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
  18         self.timer.Start(1500)
  19         self.col_num = len(self.colors)
  20         self.Centre()
  21 
  22     def OnTimer(self, event):
  23         self.panel.SetBackgroundColour(wx.RED)
  24         position = randrange(0, self.col_num-1, 1)
  25         self.panel.SetBackgroundColour(self.colors[position])
  26         self.panel.Refresh()
  27 
  28 class MyApp(wx.App):
  29     def OnInit(self):
  30         updateColourDB()
  31         frame = MyFrame(None, -1, 'randomcolours.py')
  32         frame.Show(True)
  33         self.SetTopWindow(frame)
  34         return True
  35 
  36 app = MyApp(0)
  37 app.MainLoop()

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 it's own colour. When the image custom writing 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.

There are various kinds of bitmaps:

  • PNG
  • JPEG
  • GIF
  • TIFF
  • BMP

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # bitmap.py
   4 
   5 import wx
   6 
   7 class MyFrame(wx.Frame):
   8     def __init__(self, parent, id, title):
   9         wx.Frame.__init__(self, parent, id, title, size = (270, 270))
  10 
  11         self.bitmap = wx.Bitmap('memento.jpg')
  12         wx.EVT_PAINT(self, self.OnPaint)
  13 
  14         self.Centre()
  15 
  16     def OnPaint(self, event):
  17         dc = wx.PaintDC(self)
  18         dc.DrawBitmap(self.bitmap, 60, 20)
  19 
  20 
  21 class MyApp(wx.App):
  22     def OnInit(self):
  23         frame = MyFrame(None, -1, 'Memento')
  24         frame.Show(True)
  25         self.SetTopWindow(frame)
  26         return True
  27 
  28 app = MyApp(0)
  29 app.MainLoop()

memento.png

Figure: bitmap.py

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 it's 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 writing service 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.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # myscrollwinevent.py
   4 
   5 import wx
   6 
   7 class MyScrollWinEvent(wx.Frame):
   8     def __init__(self, parent, id, title):
   9         wx.Frame.__init__(self, parent, id, title)
  10         panel = wx.Panel(self, -1)
  11         self.st = wx.StaticText(panel, -1, '0', (30,0))
  12         panel.Bind(wx.EVT_SCROLLWIN, self.OnScroll)
  13         panel.SetScrollbar(wx.VERTICAL, 0, 6, 50);
  14         self.Centre()
  15 
  16     def OnScroll(self, evt):
  17         y = evt.GetPosition()
  18         self.st.SetLabel(str(y))
  19 
  20 class MyApp(wx.App):
  21     def OnInit(self):
  22         msw = MyScrollWinEvent(None, -1, 'myscrollwinevent.py')
  23         msw.Show(True)
  24         return True
  25 
  26 app = MyApp(0)
  27 app.MainLoop()

The wx.SizeEvent is generated, when our window is resized. In our example, we show the size of the window in the titlebar.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # sizeevent.py
   4 
   5 import wx
   6 
   7 class SizeEvent(wx.Frame):
   8     def __init__(self, parent, id, title):
   9         wx.Frame.__init__(self, parent, id, title)
  10 
  11         self.Bind(wx.EVT_SIZE, self.OnSize)
  12         self.Centre()
  13 
  14     def OnSize(self, event):
  15         self.SetTitle(str(event.GetSize()))
  16 
  17 class MyApp(wx.App):
  18     def OnInit(self):
  19         se = SizeEvent(None, -1, 'sizeevent.py')
  20         se.Show(True)
  21         return True
  22 
  23 app = MyApp(0)
  24 app.MainLoop()

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # moveevent.py
   4 
   5 import wx
   6 
   7 class MoveEvent(wx.Frame):
   8     def __init__(self, parent, id, title):
   9         wx.Frame.__init__(self, parent, id, title)
  10 
  11         wx.StaticText(self, -1, 'x:', (10,0))
  12         wx.StaticText(self, -1, 'y:', (10,20))
  13         self.st1 = wx.StaticText(self, -1, '', (30, 0))
  14         self.st2 = wx.StaticText(self, -1, '', (30, 20))
  15         self.Bind(wx.EVT_MOVE, self.OnMove)
  16         self.Centre()
  17 
  18     def OnMove(self, event):
  19         x, y = event.GetPosition()
  20         self.st1.SetLabel(str(x))
  21         self.st2.SetLabel(str(y))
  22 
  23 class MyApp(wx.App):
  24     def OnInit(self):
  25         me = MoveEvent(None, -1, 'moveevent.py')
  26         me.Show(True)
  27         return True
  28 
  29 app = MyApp(0)
  30 app.MainLoop()

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.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # paintevent.py
   4 
   5 import wx
   6 
   7 class PaintEvent(wx.Frame):
   8     def __init__(self, parent, id, title):
   9         wx.Frame.__init__(self, parent, id, title)
  10 
  11         self.Bind(wx.EVT_PAINT, self.OnPaint)
  12         self.Centre()
  13 
  14     def OnPaint(self, event):
  15         wx.Bell()
  16 
  17 class MyApp(wx.App):
  18     def OnInit(self):
  19         pe = PaintEvent(None, -1, 'paintevent.py')
  20         pe.Show(True)
  21         return True
  22 
  23 app = MyApp(0)
  24 app.MainLoop()

When we press a key on our keyboard, wx.KeyEvent is generated. There are three different key handlers:

  • EVT_KEY_DOWN
  • EVT_KEY_UP
  • EVT_CHAR

A common request is to close application, when Esc key is pressed.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # keyevent.py
   4 
   5 import wx
   6 
   7 
   8 class KeyEvent(wx.Frame):
   9     def __init__(self, parent, id, title):
  10         wx.Frame.__init__(self, parent, id, title)
  11 
  12         panel = wx.Panel(self, -1)
  13         panel.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
  14         panel.SetFocus()
  15 
  16         self.Centre()
  17         self.Show(True)
  18 
  19 
  20     def OnKeyDown(self, event):
  21         keycode = event.GetKeyCode()
  22         if keycode == wx.WXK_ESCAPE:
  23             ret  = wx.MessageBox('Are you sure to quit?', 'Question', wx.YES_NO | wx.CENTRE |
  24  wx.NO_DEFAULT, self)
  25             if ret == wx.YES:
  26                 self.Close()
  27         event.Skip()
  28 
  29 
  30 app = wx.App()
  31 KeyEvent(None, -1, 'keyevent.py')
  32 app.MainLoop()

We find out, which key was pressed by calling GetKeyCode() method. In our case, keycode is wx.WXK_ESCAPE.

keycode = event.GetKeyCode()

Other keycodes are listed below.

Dialogs

In wxPython you can use predefined dialogs or create your own dialogs. You can also create dialog based applications.

The example shows a skeleton of a dialog based application in wxPython.

Toggle line numbers
   1 #!/usr/bin/python
   2 # simpledialog.py
   3 
   4 import wx
   5 
   6 class MyDialog(wx.Dialog):
   7     def __init__(self, parent, id, title):
   8         wx.Dialog.__init__(self, parent, id, title)
   9 
  10 class MyApp(wx.App):
  11     def OnInit(self):
  12         dia = MyDialog(None, -1, "simpledialog.py")
  13         dia.ShowModal()
  14         dia.Destroy()
  15         return True
  16 
  17 app = MyApp(0)
  18 app.MainLoop()

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.

CreateTextSizer(self, string message)
CreateButtonSizer(self, long flags)

CreateTextSizer() method creates a text sizer. In the following example, we add some buttons into the sizer to demonstrate it.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # customdialog1.py
   4 
   5 import wx
   6 
   7 class MyDialog(wx.Dialog):
   8     def __init__(self, parent, id, title):
   9         wx.Dialog.__init__(self, parent, id, title, size=(350,300))
  10 
  11         sizer =  self.CreateTextSizer('My Buttons')
  12         sizer.Add(wx.Button(self, -1, 'Button'), 0, wx.ALL, 5)
  13         sizer.Add(wx.Button(self, -1, 'Button'), 0, wx.ALL, 5)
  14         sizer.Add(wx.Button(self, -1, 'Button'), 0, wx.ALL, 5)
  15         sizer.Add(wx.Button(self, -1, 'Button'), 0, wx.ALL|wx.ALIGN_CENTER, 5)
  16         sizer.Add(wx.Button(self, -1, 'Button'), 0, wx.ALL|wx.EXPAND, 5)
  17         self.SetSizer(sizer)
  18 
  19 class MyFrame(wx.Frame):
  20     def __init__(self, parent, id, title):
  21         wx.Frame.__init__(self, parent, id, title, size=(550,500))
  22 
  23         panel = wx.Panel(self, -1)
  24         wx.Button(panel, 1, 'Show Custom Dialog', (100,100))
  25         self.Bind (wx.EVT_BUTTON, self.OnShowCustomDialog, id=1)
  26 
  27     def OnShowCustomDialog(self, event):
  28         dia = MyDialog(self, -1, 'buttons')
  29         dia.ShowModal()
  30         dia.Destroy()
  31 
  32 class MyApp(wx.App):
  33     def OnInit(self):
  34         frame = MyFrame(None, -1, 'customdialog1.py')
  35         frame.Show(True)
  36         frame.Centre()
  37         return True
  38 
  39 app = MyApp(0)
  40 app.MainLoop()

CreateButtonSizer() method creates a row of buttons. You can specify button types with different flags. CreateButtonSizer() method can take the following flags:

  • wx.OK
  • wx.CANCEL
  • wx.YES
  • wx.NO
  • wx.HELP
  • wx.NO_DEFAULT

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # customdialog2.py
   4 
   5 import wx
   6 
   7 class MyDialog(wx.Dialog):
   8     def __init__(self, parent, id, title):
   9         wx.Dialog.__init__(self, parent, id, title)
  10 
  11         vbox = wx.BoxSizer(wx.VERTICAL)
  12         stline = wx.StaticText(self, 11, 'Discipline ist Macht.')
  13         vbox.Add(stline, 1, wx.ALIGN_CENTER|wx.TOP, 45)
  14         sizer =  self.CreateButtonSizer(wx.NO|wx.YES|wx.HELP)
  15         vbox.Add(sizer, 0, wx.ALIGN_CENTER)
  16         self.SetSizer(vbox)
  17         self.Bind(wx.EVT_BUTTON, self.OnYes, id=wx.ID_YES)
  18 
  19     def OnYes(self, event):
  20         self.Close()
  21 
  22 class MyFrame(wx.Frame):
  23     def __init__(self, parent, id, title):
  24         wx.Frame.__init__(self, parent, id, title)
  25         panel = wx.Panel(self, -1)
  26         wx.Button(panel, 1, 'Show custom Dialog', (50,50))
  27         self.Bind(wx.EVT_BUTTON, self.OnShowCustomDialog, id=1)
  28 
  29     def OnShowCustomDialog(self, event):
  30         dia = MyDialog(self, -1, '')
  31         val = dia.ShowModal()
  32         dia.Destroy()
  33 
  34 class MyApp(wx.App):
  35     def OnInit(self):
  36         frame = MyFrame(None, -1, 'customdialog2.py')
  37         frame.Show(True)
  38         frame.Centre()
  39         return True
  40 
  41 app = MyApp(0)
  42 app.MainLoop()

Note that wxPython does not take the order of flags into account.

sizer =  self.CreateButtonSizer(wxNO|wxYES|wxHELP)

The buttons will be created according to the standards.

Common Predefined Dialogs

wxPython provides several common dialogs. They save programmers a lot of work. They also help promote standards in applications. We will show these ones:

  • wx.MessageDialog

  • wx.ColourDialog

  • wx.FileDialog

  • wx.PageSetupDialog

  • wx.FontDialog

  • wx.DirDialog

  • wx.SingleChoiceDialog

  • wx.TextEntryDialog

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # commondialogs.py
   4 
   5 import wx
   6 import os, sys
   7 
   8 class MyFrame(wx.Frame):
   9     def __init__(self, parent, id, title):
  10       wx.Frame.__init__(self, parent, id, title)
  11 
  12       self.CreateStatusBar()
  13       menuBar = wx.MenuBar()
  14       menu = wx.Menu()
  15       menu.Append(99,  "&Message Dialog", "Shows a Message Dialog")
  16       menu.Append(100, "&Color Dialog", "Shows a Color Dialog")
  17       menu.Append(101, "&File Dialog", "Shows a File Dialog")
  18       menu.Append(102, "&Page Setup Dialog", "Shows a Page Setup Dialog")
  19       menu.Append(103, "&Font Dialog", "Shows a Font Dialog")
  20       menu.Append(104, "&Directory Dialog", "Shows a Directory Dialog")
  21       menu.Append(105, "&SingleChoice Dialog", "Shows a SingleChoice Dialog")
  22       menu.Append(106, "&TextEntry Dialog", "Shows a TextEntry Dialog")
  23       menuBar.Append(menu, "&Dialogs")
  24       self.SetMenuBar(menuBar)
  25 
  26       self.Bind(wx.EVT_MENU, self.message, id=99)
  27       self.Bind(wx.EVT_MENU, self.choosecolor, id=100)
  28       self.Bind(wx.EVT_MENU, self.openfile, id=101)
  29       self.Bind(wx.EVT_MENU, self.pagesetup, id=102)
  30       self.Bind(wx.EVT_MENU, self.choosefont, id=103)
  31       self.Bind(wx.EVT_MENU, self.opendir, id=104)
  32       self.Bind(wx.EVT_MENU, self.singlechoice, id=105)
  33       self.Bind(wx.EVT_MENU, self.textentry, id=106)
  34 
  35     def message(self, event):
  36         dlg = wx.MessageDialog(self, 'To save one life is as if you have saved the world.', 'Talmud', wx.OK|wx.ICON_INFORMATION)
  37         dlg.ShowModal()
  38         dlg.Destroy()
  39 
  40     def choosecolor(self, event):
  41         dlg = wx.ColourDialog(self)
  42         dlg.GetColourData().SetChooseFull(True)
  43         if dlg.ShowModal() == wx.ID_OK:
  44             data = dlg.GetColourData()
  45             self.SetStatusText('You selected: %s\n' % str(data.GetColour().Get()))
  46         dlg.Destroy()
  47 
  48     def openfile(self, event):
  49        dlg = wx.FileDialog(self, "Choose a file", os.getcwd(), "", "*.*", wx.OPEN)
  50        if dlg.ShowModal() == wx.ID_OK:
  51                 path = dlg.GetPath()
  52                 mypath = os.path.basename(path)
  53                 self.SetStatusText("You selected: %s" % mypath)
  54        dlg.Destroy()
  55 
  56     def pagesetup(self, event):
  57         dlg = wx.PageSetupDialog(self)
  58         if dlg.ShowModal() == wx.ID_OK:
  59             data = dlg.GetPageSetupData()
  60             tl = data.GetMarginTopLeft()
  61             br = data.GetMarginBottomRight()
  62             self.SetStatusText('Margins are: %s %s' % (str(tl), str(br)))
  63         dlg.Destroy()
  64 
  65     def choosefont(self, event):
  66         default_font = wx.Font(10, wx.SWISS , wx.NORMAL, wx.NORMAL, False, "Verdana")
  67         data = wx.FontData()
  68         if sys.platform == 'win32':
  69             data.EnableEffects(True)
  70         data.SetAllowSymbols(False)
  71         data.SetInitialFont(default_font)
  72         data.SetRange(10, 30)
  73         dlg = wx.FontDialog(self, data)
  74         if dlg.ShowModal() == wx.ID_OK:
  75             data = dlg.GetFontData()
  76             font = data.GetChosenFont()
  77             color = data.GetColour()
  78             text = 'Face: %s, Size: %d, Color: %s' % (font.GetFaceName(), font.GetPointSize(),  color.Get())
  79             self.SetStatusText(text)
  80         dlg.Destroy()
  81 
  82     def opendir(self, event):
  83         dlg = wx.DirDialog(self, "Choose a directory:", style=wx.DD_DEFAULT_STYLE | wx.DD_NEW_DIR_BUTTON)
  84         if dlg.ShowModal() == wx.ID_OK:
  85             self.SetStatusText('You selected: %s\n' % dlg.GetPath())
  86         dlg.Destroy()
  87 
  88     def singlechoice(self, event):
  89         sins = ['Greed', 'Lust', 'Gluttony', 'Pride', 'Sloth', 'Envy', 'Wrath']
  90         dlg = wx.SingleChoiceDialog(self, 'Seven deadly sins', 'Which one?', sins, wx.CHOICEDLG_STYLE)
  91         if dlg.ShowModal() == wx.ID_OK:
  92             self.SetStatusText('You chose: %s\n' % dlg.GetStringSelection())
  93         dlg.Destroy()
  94 
  95     def textentry(self, event):
  96         dlg = wx.TextEntryDialog(self, 'Enter some text','Text Entry')
  97         dlg.SetValue("Default")
  98         if dlg.ShowModal() == wx.ID_OK:
  99             self.SetStatusText('You entered: %s\n' % dlg.GetValue())
 100         dlg.Destroy()
 101 
 102 class MyApp(wx.App):
 103     def OnInit(self):
 104         myframe = MyFrame(None, -1, "commondialogs.py")
 105         myframe.CenterOnScreen()
 106         myframe.Show(True)
 107         return True
 108 
 109 app = MyApp(0)
 110 app.MainLoop()

The script shows eight different common dialogs. All the output is displayed on the statusbar.

messagedialog.png textentrydialog.png

fontdialog.png colordialog.png

directorydialog.png filedialog.png

pagesetupdialog.png singlechoicedialog.png

Core Widgets

In this section, we will introduce basic widgets in wxPython. Each widget will have a small code example.

wx.Button

wx.Button is a simple widget. It contains a text string. It is used to trigger an action.

wx.Button styles

  • wx.BU_LEFT
  • wx.BU_TOP
  • wx.BU_RIGHT
  • wx.BU_BOTTOM
  • wx.BU_EXACTFIT
  • wx.NO_BORDER

wx.Button methods

SetDefault()

set the button to be the default item on a window

wx.Size GetDefaultSize()

get the default button size on a platform

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # buttons.py
   4 
   5 import wx
   6 import random
   7 
   8 APP_SIZE_X = 300
   9 APP_SIZE_Y = 200
  10 
  11 class MyButtons(wx.Dialog):
  12     def __init__(self, parent, id, title):
  13         wx.Dialog.__init__(self, parent, id, title, size=(APP_SIZE_X, APP_SIZE_Y))
  14 
  15         wx.Button(self, 1, 'Close', (50, 130))
  16         wx.Button(self, 2, 'Random Move', (150, 130), (110, -1))
  17 
  18         self.Bind(wx.EVT_BUTTON, self.OnClose, id=1)
  19         self.Bind(wx.EVT_BUTTON, self.OnRandomMove, id=2)
  20 
  21         self.Centre()
  22         self.ShowModal()
  23         self.Destroy()
  24 
  25     def OnClose(self, event):
  26         self.Close(True)
  27 
  28     def OnRandomMove(self, event):
  29         screensize = wx.GetDisplaySize()
  30         randx = random.randrange(0, screensize.x - APP_SIZE_X)
  31         randy = random.randrange(0, screensize.y - APP_SIZE_Y)
  32         self.Move((randx, randy))
  33 
  34 app = wx.App(0)
  35 MyButtons(None, -1, 'buttons.py')
  36 app.MainLoop()

buttons.png

Figure: buttons.py

wx.ToggleButton

wx.ToggleButton is a button that has two states. Pressed and not pressed. You toggle between these two states by clicking on it. There are situations where this functionality fits well.

wx.ToggleButton methods

SetValue(bool value)

set a state of a toggle button

bool GetValue()

get a state of the toggle button

SetLabel(string label)

set a label for the button

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # togglebuttons.py
   4 
   5 import wx
   6 
   7 class ToggleButtons(wx.Dialog):
   8     def __init__(self, parent, id, title):
   9         wx.Dialog.__init__(self, parent, id, title, size=(300, 200))
  10 
  11         self.colour = wx.Colour(0, 0, 0)
  12 
  13         wx.ToggleButton(self, 1, 'red', (20, 25))
  14         wx.ToggleButton(self, 2, 'green', (20, 60))
  15         wx.ToggleButton(self, 3, 'blue', (20, 100))
  16 
  17         self.panel  = wx.Panel(self, -1, (150, 20), (110, 110), style=wx.SUNKEN_BORDER)
  18         self.panel.SetBackgroundColour(self.colour)
  19 
  20         self.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleRed, id=1)
  21         self.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleGreen, id=2)
  22         self.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleBlue, id=3)
  23 
  24         self.Centre()
  25         self.ShowModal()
  26         self.Destroy()
  27 
  28     def ToggleRed(self, event):
  29         green = self.colour.Green()
  30         blue = self.colour.Blue()
  31         if  self.colour.Red():
  32             self.colour.Set(0, green, blue)
  33         else:
  34             self.colour.Set(255, green, blue)
  35         self.panel.SetBackgroundColour(self.colour)
  36 
  37     def ToggleGreen(self, event):
  38         red = self.colour.Red()
  39         blue = self.colour.Blue()
  40         if  self.colour.Green():
  41             self.colour.Set(red, 0, blue)
  42         else:
  43             self.colour.Set(red, 255, blue)
  44         self.panel.SetBackgroundColour(self.colour)
  45 
  46     def ToggleBlue(self, event):
  47         red = self.colour.Red()
  48         green = self.colour.Green()
  49         if  self.colour.Blue():
  50             self.colour.Set(red, green, 0)
  51         else:
  52             self.colour.Set(red, green, 255)
  53         self.panel.SetBackgroundColour(self.colour)
  54 
  55 
  56 app = wx.App(0)
  57 ToggleButtons(None, -1, 'togglebuttons.py')
  58 app.MainLoop()

togglebuttons.png

Figure: togglebuttons.py

wx.BitmapButton

A bitmap button is a button, that displays a bitmap. A bitmap button can have three other states. Selected, focused and displayed. We can set a specific bitmap for those states.

wx.BitmapButton methods

wx.Bitmap GetBitmapLabel()

return the label bitmap

SetBitmapLabel(wx.Bitmap bitmap)

set the bitmap label for the button

wx.Bitmap GetBitmapFocus()

return the bitmap for the focused state

wx.Bitmap GetBitmapDisabled()

return the bitmap for the disabled state

wx.Bitmap GetBitmapSelected()

return the bitmap for the selected state

SetBitmapFocus(wx.Bitmap bitmap)

set the bitmap for the focused state

SetBitmapSelected(wx.Bitmap bitmap)

set the bitmap for the selected state

SetBitmapDisabled(wx.Bitmap bitmap)

set the bitmap for the disabled state

SetMargins(int x, int y)

not implemented

int GetMarginX()

not implemented

int GetMarginY()

not implemented

A video player is a nice example, where bitmap buttons are used. We can see play, pause, next, previous and volume bitmap buttons there. So we create a skeleton of a video player in our next example.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # player.py
   4 
   5 import wx
   6 
   7 class MyFrame(wx.Frame):
   8     def __init__(self, parent, id, title):
   9         wx.Frame.__init__(self, parent, id, title, size=(350, 300))
  10         panel = wx.Panel(self, -1)
  11 
  12         pnl1 = wx.Panel(self, -1)
  13         pnl1.SetBackgroundColour(wx.BLACK)
  14         pnl2 = wx.Panel(self, -1 )
  15 
  16         menubar = wx.MenuBar()
  17         file = wx.Menu()
  18         play = wx.Menu()
  19         view = wx.Menu()
  20         tools = wx.Menu()
  21         favorites = wx.Menu()
  22         help = wx.Menu()
  23 
  24         file.Append(101, '&quit', 'Quit application')
  25 
  26         menubar.Append(file, '&File')
  27         menubar.Append(play, '&Play')
  28         menubar.Append(view, '&View')
  29         menubar.Append(tools, '&Tools')
  30         menubar.Append(favorites, 'F&avorites')
  31         menubar.Append(help, '&Help')
  32 
  33         slider1 = wx.Slider(pnl2, -1, 0, 0, 1000)
  34         pause = wx.BitmapButton(pnl2, -1, wx.Bitmap('icons/stock_media-pause.png'))
  35         play  = wx.BitmapButton(pnl2, -1, wx.Bitmap('icons/stock_media-play.png'))
  36         next  = wx.BitmapButton(pnl2, -1, wx.Bitmap('icons/stock_media-next.png'))
  37         prev  = wx.BitmapButton(pnl2, -1, wx.Bitmap('icons/stock_media-prev.png'))
  38         volume = wx.BitmapButton(pnl2, -1, wx.Bitmap('icons/volume.png'))
  39         slider2 = wx.Slider(pnl2, -1, 0, 0, 100, size=(120, -1))
  40 
  41         vbox = wx.BoxSizer(wx.VERTICAL)
  42         hbox1 = wx.BoxSizer(wx.HORIZONTAL)
  43         hbox2 = wx.BoxSizer(wx.HORIZONTAL)
  44 
  45         hbox1.Add(slider1, 1)
  46         hbox2.Add(pause)
  47         hbox2.Add(play, flag=wx.RIGHT, border=5)
  48         hbox2.Add(next, flag=wx.LEFT, border=5)
  49         hbox2.Add(prev)
  50         hbox2.Add((150, -1), 1, flag=wx.EXPAND | wx.ALIGN_RIGHT)
  51         hbox2.Add(volume, flag=wx.ALIGN_RIGHT)
  52         hbox2.Add(slider2, flag=wx.ALIGN_RIGHT | wx.TOP | wx.LEFT, border=5)
  53 
  54         vbox.Add(hbox1, 1, wx.EXPAND | wx.BOTTOM, 10)
  55         vbox.Add(hbox2, 1, wx.EXPAND)
  56         pnl2.SetSizer(vbox)
  57 
  58         sizer = wx.BoxSizer(wx.VERTICAL)
  59         sizer.Add(pnl1, 1, flag=wx.EXPAND)
  60         sizer.Add(pnl2, flag=wx.EXPAND | wx.BOTTOM | wx.TOP, border=10)
  61 
  62         self.SetMinSize((350, 300))
  63         self.SetMenuBar(menubar)
  64         self.CreateStatusBar()
  65         self.SetSizer(sizer)
  66         self.Centre()
  67 
  68 class MyApp(wx.App):
  69     def OnInit(self):
  70         frame = MyFrame(None, -1, 'Player')
  71         frame.Show(True)
  72         self.SetTopWindow(frame)
  73         return True
  74 
  75 app = MyApp(0)
  76 app.MainLoop()

player.png

Figure: player.py

wx.StaticLine

This widget displays a simple line on the window. It can be horizontal or vertical.

wx.StaticLine styles

  • wx.LI_HORIZONTAL
  • wx.LI_VERTICAL

wx.StaticLine methods

bool IsVertical()

check if the line is vertical

integer GetDefaultSize()

return the size of the line

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # centraleurope.py
   4 
   5 import wx
   6 
   7 class MyDialog(wx.Dialog):
   8     def __init__ (self, parent, ID, title):
   9         wx.Dialog.__init__(self, parent, ID, title, size=(360, 370))
  10 
  11         font = wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)
  12         heading = wx.StaticText(self, -1, 'The Central Europe', (130, 15))
  13         heading.SetFont(font)
  14 
  15         wx.StaticLine(self, -1, (25, 50), (300,1))
  16 
  17         wx.StaticText(self, -1, 'Slovakia', (25, 80), style=wx.ALIGN_RIGHT)
  18         wx.StaticText(self, -1, 'Hungary', (25, 100), style=wx.ALIGN_RIGHT)
  19         wx.StaticText(self, -1, 'Poland', (25, 120), style=wx.ALIGN_RIGHT)
  20         wx.StaticText(self, -1, 'Czech Republic', (25, 140))
  21         wx.StaticText(self, -1, 'Germany', (25, 160))
  22         wx.StaticText(self, -1, 'Slovenia', (25, 180))
  23         wx.StaticText(self, -1, 'Austria', (25, 200))
  24         wx.StaticText(self, -1, 'Switzerland', (25, 220))
  25 
  26         wx.StaticText(self, -1, '5 379 000', (250, 80))
  27         wx.StaticText(self, -1, '10 084 000', (250, 100))
  28         wx.StaticText(self, -1, '38 635 000', (250, 120))
  29         wx.StaticText(self, -1, '10 240 000', (250, 140))
  30         wx.StaticText(self, -1, '82 443 000', (250, 160))
  31         wx.StaticText(self, -1, '2 001 000', (250, 180))
  32         wx.StaticText(self, -1, '8 032 000', (250, 200))
  33         wx.StaticText(self, -1, '7 288 000', (250, 220))
  34 
  35         wx.StaticLine(self, -1, (25, 260), (300,1))
  36 
  37         sum = wx.StaticText(self, -1, '164 102 000', (240, 280))
  38         sum_font = sum.GetFont()
  39         sum_font.SetWeight(wx.BOLD)
  40         sum.SetFont(sum_font)
  41 
  42         wx.Button(self, 1, 'Ok', (140, 310), (60, 30))
  43 
  44         self.Bind(wx.EVT_BUTTON, self.OnOk, id=1)
  45         self.Centre()
  46 
  47     def OnOk(self, event):
  48         self.Close()
  49 
  50 class MyApp(wx.App):
  51     def OnInit(self):
  52         dia = MyDialog(None, -1, 'centraleurope.py')
  53         dia.ShowModal()
  54         dia.Destroy()
  55         return True
  56 
  57 app = MyApp()
  58 app.MainLoop()

centraleurope.py script displays central european countries and their population. Thewx.StatLine makes it look more visually attractive.

centraleurope.png

Figure: centraleurope.py

wx.StaticText

Awx.StaticText widget displays one or more lines of read-only text.

wx.StaticText Styles

  • wx.ALIGN_RIGHT
  • wx.ALIGN_LEFT
  • wx.ALIGN_CENTER / wx.ALIGN_CENTRE
  • wx.ST_NO_AUTORESIZE

wx.StaticText methods

Wrap(int width)

if possible set each line of text to width pixels. if width is negative, no wrapping is done.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # statictext.py
   4 
   5 import wx
   6 
   7 class MyFrame(wx.Frame):
   8     def __init__(self, parent, id, title):
   9         wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(320, 350))
  10 
  11         lyrics1 = '''I'm giving up the ghost of love
  12 in the shadows cast on devotion
  13 She is the one that I adore
  14 creed of my silent suffocation
  15 Break this bittersweet spell on me
  16 lost in the arms of destiny'''
  17 
  18         lyrics2 = '''There is something in the way
  19 You're always somewhere else
  20 Feelings have deserted me
  21 To a point of no return
  22 I don't believe in God
  23 But I pray for you'''
  24 
  25         panel = wx.Panel(self, -1)
  26         wx.StaticText(panel, -1, lyrics1, (45, 25), style=wx.ALIGN_CENTRE)
  27         wx.StaticText(panel, -1, lyrics2, (45, 190), style=wx.ALIGN_CENTRE)
  28         self.Centre()
  29 
  30 class MyApp(wx.App):
  31     def OnInit(self):
  32         frame = MyFrame(None, -1, 'statictext.py')
  33         frame.Show(True)
  34         self.SetTopWindow(frame)
  35         return True
  36 
  37 app = MyApp(0)
  38 app.MainLoop()

statictext.png

Figure statictext.py

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.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # staticbox.py
   4 
   5 import wx
   6 
   7 class MyDialog(wx.Dialog):
   8     def __init__(self, parent, id, title):
   9         wx.Dialog.__init__(self, parent, id, title, size=(250, 230))
  10 
  11         wx.StaticBox(self, -1, 'Personal Info', (5, 5), size=(240, 170))
  12         wx.CheckBox(self, -1 ,'Male', (15, 30))
  13         wx.CheckBox(self, -1 ,'Married', (15, 55))
  14         wx.StaticText(self, -1, 'Age', (15, 95))
  15         wx.SpinCtrl(self, -1, '1', (55, 90), (60, -1), min=1, max=120)
  16         wx.Button(self, 1, 'Ok', (90, 185), (60, -1))
  17 
  18         self.Bind(wx.EVT_BUTTON, self.OnClose, id=1)
  19 
  20         self.Centre()
  21         self.ShowModal()
  22         self.Destroy()
  23 
  24     def OnClose(self, event):
  25         self.Close()
  26 
  27 app = wx.App(0)
  28 MyDialog(None, -1, 'staticbox.py')
  29 app.MainLoop()

staticbox.png

Figure staticbox.py

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.ComboBox has the following constructor:

wx.ComboBox(int id, string value='', wx.Point pos=wx.DefaultPosition, wx.Size size=wx.DefaultSize,
            wx.List choices=wx.EmptyList, int style=0, wx.Validator validator=wx.DefaultValidator,
            string name=wx.ComboBoxNameStr)

wx.ComboBox styles

  • wx.CB_DROPDOWN
  • wx.CB_READONLY
  • wx.CB_SORT

wx.ComboBox methods

string GetValue()

return the current value

SetValue(string value)

set the value into the textfield of the combobox

Copy()

copy the selected value to the clipboard

Cut()

cut the selected value to the clipboard

Paste()

paste text from the clipboard to the combobox's text field

SetInsertionPoint(int pos)

set the insertion point in the combobox's text field

int GetInsertionPoint()

get the insertion point for the combobox's text field

int GetLastPosition()

return the last position in the combobox's text field

Replace(int from, int to, string value)

replace the text between from and to positions in the combobox's text field

SetSelection(int n)

select the item at position n

SetMark(int from, int to)

select the text between from and to positions in the combobox's text field

(int from, int to) GetMark()

return the from and to positions of the selected text in the combobox's text field

int GetCurrentSelection()

return the current selection

bool SetStringSelection(string string)

select the item with the specified string

int SetString(int n, string string)

set the label for the item at position n

bool SetEditable(bool editable)

toggle readonly flag for the combobox's text field

int SetInsertionPointEnd()

set the insertion point at the end of the combobox's text field.

Remove(int from, int to)

remove the text between the two positions in the combobox's text field

bool IsEditable()

return true if the combobox is editable

SelectAll(int from, int to)

select all the text in the combo's text field

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # combobox.py
   4 
   5 import wx
   6 
   7 class MyDialog(wx.Dialog):
   8     def __init__(self, parent, id, title):
   9         wx.Dialog.__init__(self, parent, id, title, size=(250, 270))
  10 
  11         panel = wx.Panel(self, -1, (75, 20), (100, 127),  style=wx.SUNKEN_BORDER)
  12         self.picture = wx.StaticBitmap(panel)
  13         panel.SetBackgroundColour(wx.WHITE)
  14 
  15         self.images = ['tolstoy.jpg', 'feuchtwanger.jpg', 'balzac.jpg', 'pasternak.jpg', 'galsworthy.jpg', 'wolfe.jpg', 'zweig.jpg']
  16         authors = ['Leo Tolstoy', 'Lion Feuchtwanger', 'Honore de Balzac', 'Boris Pasternak', 'John Galsworthy', 'Tom Wolfe', 'Stefan Zweig' ]
  17 
  18 
  19         wx.ComboBox(self, -1, pos=(50, 170), size=(150, -1), choices=authors, style=wx.CB_READONLY)
  20         wx.Button(self, 1, 'Close', (80, 220))
  21 
  22         self.Bind(wx.EVT_BUTTON, self.OnClose, id=1)
  23         self.Bind(wx.EVT_COMBOBOX, self.OnSelect)
  24 
  25         self.Centre()
  26 
  27     def OnClose(self, event):
  28         self.Close()
  29 
  30     def OnSelect(self, event):
  31         item = event.GetSelection()
  32         self.picture.SetFocus()
  33         self.picture.SetBitmap(wx.Bitmap('images/' + self.images[item]))
  34 
  35 
  36 class MyApp(wx.App):
  37     def OnInit(self):
  38         dlg = MyDialog(None, -1, 'combobox.py')
  39         dlg.ShowModal()
  40         dlg.Destroy()
  41         return True
  42 
  43 app = MyApp(0)
  44 app.MainLoop()

combobox.png

Figure: combobox.py

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.CheckBox Styles

  • wx.ALIGN_RIGHT

wx.CheckBox methods

bool GetValue()

get the state of the checkbox

bool IsChecked()

determine the checkbox state

SetValue(bool state)

set the state of the checkbox

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # checkbox.py
   4 
   5 import wx
   6 
   7 class MyCheckBox(wx.Frame):
   8     def __init__(self, parent, id, title):
   9         wx.Frame.__init__(self, parent, id, title, size=(250, 170))
  10 
  11         panel = wx.Panel(self, -1)
  12         self.cb = wx.CheckBox(panel, -1, 'Show Title', (10, 10))
  13         self.cb.SetValue(True)
  14 
  15         wx.EVT_CHECKBOX(self, self.cb.GetId(), self.ShowTitle)
  16 
  17         self.Show()
  18         self.Centre()
  19 
  20     def ShowTitle(self, event):
  21         if self.cb.GetValue():
  22             self.SetTitle('checkbox.py')
  23         else: self.SetTitle('')
  24 
  25 
  26 app = wx.App(0)
  27 MyCheckBox(None, -1, 'checkbox.py')
  28 app.MainLoop()

In our script we toggle the visibility of the title.

checkbox.png

Figure: checkbox.py

wx.StatusBar

As it's 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, it's description is shown on the wx.StatusBar

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # statusbar.py
   4 
   5 import wx
   6 
   7 class MyStatusBar(wx.Frame):
   8         def __init__(self, parent, id, title):
   9                 wx.Frame.__init__(self, parent, id, title, size=(250, 200), style=wx.CAPTION | wx.SYSTEM_MENU | wx.CLOSE_BOX)
  10 
  11                 panel = wx.Panel(self, 1)
  12 
  13                 button = wx.Button(panel, 2, 'Button', (20, 20))
  14                 text = wx.CheckBox(panel, 3, 'CheckBox', (20, 90))
  15                 combo = wx.ComboBox(panel, 4, '', (120, 22))
  16                 slider = wx.Slider(panel, 5, 6, 1, 10, (120, 90), (110, -1))
  17 
  18 
  19                 panel.Bind(wx.EVT_ENTER_WINDOW, self.EnterPanel, id=1)
  20                 button.Bind(wx.EVT_ENTER_WINDOW, self.EnterButton, id=2)
  21                 text.Bind(wx.EVT_ENTER_WINDOW, self.EnterText, id=3)
  22                 combo.Bind(wx.EVT_ENTER_WINDOW, self.EnterCombo, id=4)
  23                 slider.Bind(wx.EVT_ENTER_WINDOW, self.EnterSlider, id=5)
  24 
  25 
  26                 self.sb = self.CreateStatusBar()
  27                 self.SetMaxSize((250, 200))
  28                 self.SetMinSize((250, 200))
  29                 self.Centre()
  30 
  31 
  32         def EnterButton(self, event):
  33                 self.sb.SetStatusText('Button widget')
  34                 event.Skip()
  35 
  36         def EnterPanel(self, event):
  37                 self.sb.SetStatusText('Panel widget')
  38                 event.Skip()
  39 
  40         def EnterText(self, event):
  41                 self.sb.SetStatusText('CheckBox widget')
  42                 event.Skip()
  43 
  44         def EnterCombo(self, event):
  45                 self.sb.SetStatusText('ComboBox widget')
  46                 event.Skip()
  47 
  48         def EnterSlider(self, event):
  49                 self.sb.SetStatusText('Slider widget')
  50                 event.Skip()
  51 
  52 class MyApp(wx.App):
  53         def OnInit(self):
  54                 frame = MyStatusBar(None, -1, 'statusbar.py')
  55                 frame.Show(True)
  56                 return True
  57 
  58 app = MyApp(0)
  59 app.MainLoop()

statusbar.png

Figure: statusbar.py

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.RadioButton Styles

  • wx.RB_GROUP
  • wx.RB_SINGLE

wx.RadioButton methods

bool GetValue()

returns True or False depending on the selection state

SetValue(bool state)

RadioButton

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # radiobuttons.py
   4 
   5 import wx
   6 
   7 class MyFrame(wx.Frame):
   8     def __init__(self, parent, id, title):
   9         wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(200, 150))
  10         panel = wx.Panel(self, -1)
  11         self.rb1 = wx.RadioButton(panel, -1, 'Value A', (10, 10), style=wx.RB_GROUP)
  12         self.rb2 = wx.RadioButton(panel, -1, 'Value B', (10, 30))
  13         self.rb3 = wx.RadioButton(panel, -1, 'Value C', (10, 50))
  14         self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.rb1.GetId())
  15         self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.rb2.GetId())
  16         self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.rb3.GetId())
  17         self.statusbar = self.CreateStatusBar(3)
  18         self.SetVal(True)
  19 
  20     def SetVal(self, event):
  21         state1 = str(self.rb1.GetValue())
  22         state2 = str(self.rb2.GetValue())
  23         state3 = str(self.rb3.GetValue())
  24         self.statusbar.SetStatusText(state1,0)
  25         self.statusbar.SetStatusText(state2,1)
  26         self.statusbar.SetStatusText(state3,2)
  27 
  28 class MyApp(wx.App):
  29     def OnInit(self):
  30         frame = MyFrame(None, -1, 'radiobuttons.py')
  31         frame.Show(True)
  32         frame.Center()
  33         return True
  34 
  35 app = MyApp(0)
  36 app.MainLoop()

radiobuttons.png

Figure: radiobuttons.py

wx.Gauge

wx.Gauge is a widget that is used, when we process lengthy tasks.

wx.Gauge styles

  • wx.GA_HORIZONTAL
  • wx.GA_VERTICAL

wx.Gauge methods

SetRange(integer range)

set the maximum value of the gauge

integer GetRange()

get the maximum value of the gauge

SetValue(integer position)

set the position of the gauge

integer GetValue()

get the position of the gauge

bool IsVertical()

check if the gauge is vertical

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # gauge.py
   4 
   5 import wx
   6 
   7 class MyFrame(wx.Frame):
   8     def __init__(self, parent, id, title):
   9         wx.Frame.__init__(self, parent, id, title)
  10 
  11         self.timer = wx.Timer(self, 1)
  12         self.count = 0
  13         self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
  14         panel = wx.Panel(self, -1)
  15         vbox = wx.BoxSizer(wx.VERTICAL)
  16         hbox1 = wx.BoxSizer(wx.HORIZONTAL)
  17         hbox2 = wx.BoxSizer(wx.HORIZONTAL)
  18         hbox3 = wx.BoxSizer(wx.HORIZONTAL)
  19 
  20         self.gauge = wx.Gauge(panel, -1, 50, size=(250, 25))
  21         self.btn1 = wx.Button(panel, wx.ID_OK)
  22         self.btn2 = wx.Button(panel, wx.ID_STOP)
  23         self.text = wx.StaticText(panel, -1, 'Task to be done')
  24 
  25         self.Bind(wx.EVT_BUTTON, self.OnOk, self.btn1)
  26         self.Bind(wx.EVT_BUTTON, self.OnStop, self.btn2)
  27 
  28         hbox1.Add(self.gauge, 1, wx.ALIGN_CENTRE)
  29         hbox2.Add(self.btn1, 1, wx.RIGHT, 10)
  30         hbox2.Add(self.btn2, 1)
  31         hbox3.Add(self.text, 1)
  32         vbox.Add((0, 50), 0)
  33         vbox.Add(hbox1, 0, wx.ALIGN_CENTRE)
  34         vbox.Add((0, 30), 0)
  35         vbox.Add(hbox2, 1, wx.ALIGN_CENTRE)
  36         vbox.Add(hbox3, 1, wx.ALIGN_CENTRE)
  37         panel.SetSizer(vbox)
  38         self.Centre()
  39 
  40     def OnOk(self, event):
  41         if self.count >= 50:
  42             return
  43         self.timer.Start(100)
  44         self.text.SetLabel('Task in Progress')
  45 
  46     def OnStop(self, event):
  47         if self.count == 0 or self.count >= 50 or not self.timer.IsRunning():
  48             return
  49         self.timer.Stop()
  50         self.text.SetLabel('Task Interrupted')
  51         wx.Bell()
  52 
  53     def OnTimer(self, event):
  54         self.count = self.count +1
  55         self.gauge.SetValue(self.count)
  56         if self.count == 50:
  57             self.timer.Stop()
  58             self.text.SetLabel('Task Completed')
  59 
  60 class MyApp(wx.App):
  61     def OnInit(self):
  62         frame = MyFrame(None, -1, 'gauge.py')
  63         frame.Show(True)
  64         return True
  65 
  66 app = MyApp(0)
  67 app.MainLoop()

gauge.png

Figure: gauge.py

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.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # slider.py
   4 
   5 import wx
   6 
   7 class MyFrame(wx.Frame):
   8     def __init__(self, parent, id, title):
   9 
  10         wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, (300, 150))
  11         panel = wx.Panel(self, -1)
  12 
  13         vbox = wx.BoxSizer(wx.VERTICAL)
  14         hbox = wx.BoxSizer(wx.HORIZONTAL)
  15         self.sld = wx.Slider(panel, -1, 200, 150, 500, wx.DefaultPosition, (250, -1),
  16                               wx.SL_AUTOTICKS | wx.SL_HORIZONTAL | wx.SL_LABELS)
  17         btn1 = wx.Button(panel, 8, 'Adjust')
  18         btn2 = wx.Button(panel, 9, 'Close')
  19 
  20         wx.EVT_BUTTON(self, 8, self.OnAdjust)
  21         wx.EVT_BUTTON(self, 9, self.OnClose)
  22         vbox.Add(self.sld, 1, wx.ALIGN_CENTRE)
  23         hbox.Add(btn1, 1, wx.RIGHT, 10)
  24         hbox.Add(btn2, 1)
  25         vbox.Add(hbox, 0, wx.ALIGN_CENTRE | wx.ALL, 20)
  26         panel.SetSizer(vbox)
  27 
  28     def OnAdjust(self, event):
  29         val = self.sld.GetValue()
  30 
  31         self.SetSize((val*2, val))
  32     def OnClose(self, event):
  33         self.Close()
  34 
  35 class MyApp(wx.App):
  36     def OnInit(self):
  37         frame = MyFrame(None, -1, 'slider.py')
  38         frame.Show(True)
  39         frame.Centre()
  40         return True
  41 
  42 app = MyApp(0)
  43 app.MainLoop()

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.

slider.png

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.

Toggle line numbers
   1 #!/usr/bin/python
   2 # listbox.py
   3 
   4 import wx
   5 
   6 from time import *
   7 
   8 class MyFrame(wx.Frame):
   9     def __init__(self, parent, id, title):
  10         wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, (550, 350))
  11 
  12         zone_list = ['CET', 'GMT', 'MSK', 'EST', 'PST', 'EDT']
  13         self.full_list = {
  14             'CET': 'Central European Time',
  15             'GMT': 'Greenwich Mean Time',
  16             'MSK': 'Moscow Time',
  17             'EST': 'Eastern Standard Time',
  18             'PST': 'Pacific Standard Time',
  19             'EDT': 'Eastern Daylight Time'
  20         }
  21         self.time_diff = {
  22             'CET' : 1,
  23             'GMT' : 0,
  24             'MSK': 3,
  25             'EST': -5,
  26             'PST': -8,
  27             'EDT': -4
  28         }
  29 
  30         vbox = wx.BoxSizer(wx.VERTICAL)
  31         hbox1 = wx.BoxSizer(wx.HORIZONTAL)
  32         hbox2 = wx.BoxSizer(wx.HORIZONTAL)
  33         hbox3 = wx.BoxSizer(wx.HORIZONTAL)
  34 
  35         self.timer = wx.Timer(self, 1)
  36         self.diff = 0
  37         panel = wx.Panel(self, -1)
  38         self.time_zones = wx.ListBox(panel, 26, wx.DefaultPosition, (170, 130), zone_list, wx.LB_SINGLE)
  39         self.time_zones.SetSelection(0)
  40         self.text = wx.TextCtrl(panel, -1, 'Central European Time', size=(200, 130), style=wx.TE_MULTILINE)
  41         self.time = wx.StaticText(panel, -1, '')
  42         btn = wx.Button(panel, wx.ID_CLOSE, 'Close')
  43         hbox1.Add(self.time_zones, 0, wx.TOP, 40)
  44         hbox1.Add(self.text, 1, wx.LEFT | wx.TOP, 40)
  45         hbox2.Add(self.time, 1, wx.ALIGN_CENTRE)
  46         hbox3.Add(btn, 0, wx.ALIGN_CENTRE)
  47         vbox.Add(hbox1, 0, wx.ALIGN_CENTRE)
  48         vbox.Add(hbox2, 1, wx.ALIGN_CENTRE)
  49         vbox.Add(hbox3, 1, wx.ALIGN_CENTRE)
  50         panel.SetSizer(vbox)
  51         self.timer.Start(100)
  52 
  53         self.Bind(wx.EVT_BUTTON, self.OnClose, id=wx.ID_CLOSE)
  54         self.Bind(wx.EVT_LISTBOX, self.OnSelect, id=26)
  55         self.Bind(wx.EVT_TIMER, self.OnTimer, id=1)
  56 
  57     def OnClose(self, event):
  58         self.Close()
  59 
  60     def OnSelect(self, event):
  61         index = event.GetSelection()
  62         time_zone = self.time_zones.GetString(index)
  63         self.diff = self.time_diff[time_zone]
  64         self.text.SetValue(self.full_list[time_zone])
  65 
  66     def OnTimer(self, event):
  67         ct = gmtime()
  68         print_time = (ct[0], ct[1], ct[2], ct[3]+self.diff, ct[4], ct[5], ct[6], ct[7], -1)
  69         self.time.SetLabel(strftime("%H:%M:%S", print_time))
  70 
  71 class MyApp(wx.App):
  72     def OnInit(self):
  73         frame = MyFrame(None, -1, 'listbox.py')
  74         frame.Centre()
  75         frame.Show(True)
  76         return True
  77 
  78 app = MyApp(0)
  79 app.MainLoop()

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.

listbox.png

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.

wx.SpinCtrl styles

  • wx.SP_ARROW_KEYS
  • wx.SP_WRAP

wx.SpinCtrl methods

integer GetValue()

get the current value

SetValue(integer value)

set the current value

SetValueString(string value)

something

SetRange(integer min, integer max)

set the min and max values

integer GetMin()

get the minimum value

integer GetMax()

get the maximum value

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # spinctrl.py
   4 
   5 import wx
   6 
   7 class MyDialog(wx.Dialog):
   8     def __init__(self, parent, id, title):
   9         wx.Dialog.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(350, 310))
  10 
  11         wx.StaticText(self, -1, 'Convert Fahrenheit temperature to Celsius', (20,20))
  12         wx.StaticText(self, -1, 'Fahrenheit: ', (20, 80))
  13         wx.StaticText(self, -1, 'Celsius: ', (20, 150))
  14 
  15         self.celsius =  wx.StaticText(self, -1, '', (150, 150))
  16         self.sc = wx.SpinCtrl(self, -1, '',  (150, 75), (60, -1))
  17         self.sc.SetRange(-459, 1000)
  18         self.sc.SetValue(0)
  19 
  20         compute_btn = wx.Button(self, 1, 'Compute', (70, 250))
  21         compute_btn.SetFocus()
  22         clear_btn = wx.Button(self, 2, 'Close', (185, 250))
  23 
  24         self.Bind(wx.EVT_BUTTON, self.OnCompute, id=1)
  25         self.Bind(wx.EVT_BUTTON, self.OnClose, id=2)
  26         self.Bind(wx.EVT_CLOSE, self.OnClose)
  27 
  28     def OnCompute(self, event):
  29         fahr = self.sc.GetValue()
  30         cels = round((fahr-32)*5/9.0, 2)
  31         self.celsius.SetLabel(str(cels))
  32 
  33     def OnClose(self, event):
  34         self.Destroy()
  35 
  36 class MyApp(wx.App):
  37     def OnInit(self):
  38         dlg = MyDialog(None, -1, 'spinctrl.py')
  39         dlg.Show(True)
  40         dlg.Centre()
  41         return True
  42 
  43 app = MyApp(0)
  44 app.MainLoop()

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.

spinctrl.png

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.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # capitals.py
   4 
   5 import wx
   6 
   7 class MyDialog(wx.Dialog):
   8     def __init__(self, parent, id, title):
   9         wx.Dialog.__init__(self, parent, id, title, size=(600,500), style=wx.DEFAULT_DIALOG_STYLE)
  10 
  11         hbox  = wx.BoxSizer(wx.HORIZONTAL)
  12         vbox1 = wx.BoxSizer(wx.VERTICAL)
  13         vbox2 = wx.BoxSizer(wx.VERTICAL)
  14         vbox3 = wx.GridSizer(2,2,0,0)
  15         vbox4 = wx.BoxSizer(wx.VERTICAL)
  16         pnl1 = wx.Panel(self, -1, style=wx.SIMPLE_BORDER)
  17         pnl2 = wx.Panel(self, -1, style=wx.SIMPLE_BORDER)
  18         self.lc = wx.ListCtrl(self, -1, style=wx.LC_REPORT)
  19         self.lc.InsertColumn(0, 'State')
  20         self.lc.InsertColumn(1, 'Capital')
  21         self.lc.SetColumnWidth(0, 140)
  22         self.lc.SetColumnWidth(1, 153)
  23         vbox1.Add(pnl1, 1, wx.EXPAND | wx.ALL, 3)
  24         vbox1.Add(pnl2, 1, wx.EXPAND | wx.ALL, 3)
  25         vbox2.Add(self.lc, 1, wx.EXPAND | wx.ALL, 3)
  26         self.tc1 = wx.TextCtrl(pnl1, -1)
  27         self.tc2 = wx.TextCtrl(pnl1, -1)
  28         vbox3.AddMany([ (wx.StaticText(pnl1, -1, 'State'),0, wx.ALIGN_CENTER),
  29                         (self.tc1, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL),
  30                         (wx.StaticText(pnl1, -1, 'Capital'),0, wx.ALIGN_CENTER_HORIZONTAL),
  31                         (self.tc2,0)])
  32         pnl1.SetSizer(vbox3)
  33         vbox4.Add(wx.Button(pnl2, 10, 'Add'),   0, wx.ALIGN_CENTER| wx.TOP, 45)
  34         vbox4.Add(wx.Button(pnl2, 11, 'Remove'), 0, wx.ALIGN_CENTER|wx.TOP, 15)
  35         vbox4.Add(wx.Button(pnl2, 12, 'Clear'), 0, wx.ALIGN_CENTER| wx.TOP, 15)
  36         vbox4.Add(wx.Button(pnl2, 13, 'Close'), 0, wx.ALIGN_CENTER| wx.TOP, 15)
  37         pnl2.SetSizer(vbox4)
  38         self.Bind (wx.EVT_BUTTON, self.OnAdd, id=10)
  39         self.Bind (wx.EVT_BUTTON, self.OnRemove, id=11)
  40         self.Bind (wx.EVT_BUTTON, self.OnClear, id=12)
  41         self.Bind (wx.EVT_BUTTON, self.OnClose, id=13)
  42         hbox.Add(vbox1, 1, wx.EXPAND)
  43         hbox.Add(vbox2, 1, wx.EXPAND)
  44         self.SetSizer(hbox)
  45 
  46     def OnAdd(self, event):
  47         if not self.tc1.GetValue() or not self.tc2.GetValue():
  48             return
  49         num_items = self.lc.GetItemCount()
  50         self.lc.InsertStringItem(num_items, self.tc1.GetValue())
  51         self.lc.SetStringItem(num_items, 1, self.tc2.GetValue())
  52         self.tc1.Clear()
  53         self.tc2.Clear()
  54 
  55     def OnRemove(self, event):
  56         index = self.lc.GetFocusedItem()
  57         self.lc.DeleteItem(index)
  58 
  59     def OnClose(self, event):
  60         self.Close()
  61 
  62     def OnClear(self, event):
  63         self.lc.DeleteAllItems()
  64 
  65 class MyApp(wx.App):
  66     def OnInit(self):
  67         dia = MyDialog(None, -1, 'capitals.py')
  68         dia.ShowModal()
  69         dia.Destroy()
  70         return True
  71 
  72 app = MyApp(0)
  73 app.MainLoop()

capitals1.png

Figure: capitals.py

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.

Toggle line numbers
   1 #!/usr/bin/python
   2 # splitterwindow.py
   3 import wx
   4 class MyFrame(wx.Frame):
   5     def __init__(self, parent, id, title):
   6         wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(350, 300))
   7 
   8         splitter = wx.SplitterWindow(self, -1)
   9         panel1 = wx.Panel(splitter, -1)
  10         wx.StaticText(panel1, -1,
  11                     "Whether you think that you can, or that you can't, you are usually right."
  12                     "\n\n [[http://www.fordpartsgateway.co.uk/fordfocusparts.php | Ford Focus Parts]]",
  13             (100,100), style=wx.ALIGN_CENTRE)
  14         panel1.SetBackgroundColour(wx.LIGHT_GREY)
  15         panel2 = wx.Panel(splitter, -1)
  16         panel2.SetBackgroundColour(wx.WHITE)
  17         splitter.SplitVertically(panel1, panel2)
  18         self.Centre()
  19 
  20 class MyApp(wx.App):
  21     def OnInit(self):
  22         frame = MyFrame(None, -1, 'splitterwindow.py')
  23         frame.Show(True)
  24         self.SetTopWindow(frame)
  25         return True
  26 
  27 app = MyApp(0)
  28 app.MainLoop()

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.

wx.ScrolledWindow methods

SetScrollbars()

set scrollbars for a window

Scroll(int x, int y)

scroll a window

int GetScrollPageSize(int orient)

get the scroll page size

SetScrollPageSize(int orient, int pageSize)

set the scroll page size

SetScrollRate(int xstep, int ystep)

set scrolling rate

wx.Size GetScrollPixelsPerUnit()

get the size of one logical unit in physical units

SetScrollRate(int xstep, int ystep)

set scrolling rate

EnableScrolling(bool x, bool y)

enable or disable scrolling

wxPoint GetViewStart()

get the view start

SetTargetWindow(wx.Window target)

set the target window for scrolling

wx.Window GetTargetWindow()

get the scrolling target window

AdjustScrollbars()

adjust scrollbars

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # myscrolledwindow.py
   4 
   5 import wx
   6 
   7 class MyScrolledWindow(wx.Frame):
   8    def __init__(self, parent, id, title):
   9        wx.Frame.__init__(self, parent, id, title, size=(500, 400))
  10 
  11        sw = wx.ScrolledWindow(self)
  12        bmp = wx.Image('aliens.jpg',wx.BITMAP_TYPE_JPEG).ConvertToBitmap()
  13        wx.StaticBitmap(sw, -1, bmp)
  14        sw.SetScrollbars(20,20,55,40)
  15 
  16 class MyApp(wx.App):
  17    def OnInit(self):
  18        frame = MyScrolledWindow(None, -1, 'Aliens')
  19        frame.Show(True)
  20        frame.Centre()
  21        return True
  22 
  23 app = MyApp(0)
  24 app.MainLoop()

scrolledwindow.png

wx.TreeCtrl

wx.TreeCtrl displays data in a hierarchy.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # treectrl.py
   4 
   5 import wx
   6 
   7 class MyFrame(wx.Frame):
   8     def __init__(self, parent, id, title):
   9         wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(450, 350))
  10 
  11         hbox = wx.BoxSizer(wx.HORIZONTAL)
  12         vbox = wx.BoxSizer(wx.VERTICAL)
  13         panel1 = wx.Panel(self, -1)
  14         panel2 = wx.Panel(self, -1)
  15 
  16         self.tree = wx.TreeCtrl(panel1, 1, wx.DefaultPosition, (-1,-1), wx.TR_HIDE_ROOT|wx.TR_HAS_BUTTONS)
  17         root = self.tree.AddRoot('Programmer')
  18         os = self.tree.AppendItem(root, 'Operating Systems')
  19         pl = self.tree.AppendItem(root, 'Programming Languages')
  20         tk = self.tree.AppendItem(root, 'Toolkits')
  21         self.tree.AppendItem(os, 'Linux')
  22         self.tree.AppendItem(os, 'FreeBSD')
  23         self.tree.AppendItem(os, 'OpenBSD')
  24         self.tree.AppendItem(os, 'NetBSD')
  25         self.tree.AppendItem(os, 'Solaris')
  26         cl = self.tree.AppendItem(pl, 'Compiled languages')
  27         sl = self.tree.AppendItem(pl, 'Scripting languages')
  28         self.tree.AppendItem(cl, 'Java')
  29         self.tree.AppendItem(cl, 'C++')
  30         self.tree.AppendItem(cl, 'C')
  31         self.tree.AppendItem(cl, 'Pascal')
  32         self.tree.AppendItem(sl, 'Python')
  33         self.tree.AppendItem(sl, 'Ruby')
  34         self.tree.AppendItem(sl, 'Tcl')
  35         self.tree.AppendItem(sl, 'PHP')
  36         self.tree.AppendItem(tk, 'Qt')
  37         self.tree.AppendItem(tk, 'MFC')
  38         self.tree.AppendItem(tk, 'wxPython')
  39         self.tree.AppendItem(tk, 'GTK+')
  40         self.tree.AppendItem(tk, 'Swing')
  41         self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged, id=1)
  42         self.display = wx.StaticText(panel2, -1, '',(10,10), style=wx.ALIGN_CENTRE)
  43         vbox.Add(self.tree, 1, wx.EXPAND)
  44         hbox.Add(panel1, 1, wx.EXPAND)
  45         hbox.Add(panel2, 1, wx.EXPAND)
  46         panel1.SetSizer(vbox)
  47         self.SetSizer(hbox)
  48         self.Centre()
  49 
  50     def OnSelChanged(self, event):
  51         item =  event.GetItem()
  52         self.display.SetLabel(self.tree.GetItemText(item))
  53 
  54 class MyApp(wx.App):
  55     def OnInit(self):
  56         frame = MyFrame(None, -1, 'treectrl.py')
  57         frame.Show(True)
  58         self.SetTopWindow(frame)
  59         return True
  60 
  61 app = MyApp(0)
  62 app.MainLoop()

First of all we must create a root item.

root = self.tree.AddRoot('Programmer')

In our case, root item will not be displayed, because we used wx.TR_HIDE_ROOT flag in our constructor.

self.tree = wx.TreeCtrl(panel1, 1, wx.DefaultPosition, (-1,-1), wx.TR_HIDE_ROOT|wx.TR_HAS_BUTTONS)

We add items to the root item withAppendItem() method.

os = self.tree.AppendItem(root, 'Operating Systems')
pl = self.tree.AppendItem(root, 'Programming Languages')
tk = self.tree.AppendItem(root, 'Toolkits')

We can similarly create several levels by simply adding items to existing items.

We catch events with wx.EVT_TREE_SEL_CHANGED() event handler.

wx.EVT_TREE_SEL_CHANGED(self.tree, 1, self.OnSelChanged)

Various constructor style flags:

  • TR_NO_BUTTONS
  • TR_HAS_BUTTONS
  • TR_NO_LINES
  • TR_LINES_AT_ROOT
  • TR_SINGLE
  • TR_MULTIPLE
  • TR_EXTENDED
  • TR_HAS_VARIABLE_ROW_HEIGHT
  • TR_EDIT_LABELS
  • TR_HIDE_ROOT
  • TR_ROW_LINES
  • TR_FULL_ROW_HIGHLIGHT
  • TR_DEFAULT_STYLE
  • TR_TWIST_BUTTONS
  • TR_MAC_BUTTONS
  • TR_AQUA_BUTTONS

treecontrol.png

Figure: treectrl.py

wx.Notebook

wx.Notebook widget joins multiple windows with corresponding tabs.

You can position the Notebook widget using the following style flags:

  • wx.NB_LEFT
  • wx.NB_RIGHT
  • wx.NB_TOP
  • wx.NB_BOTTOM

The default position is wx.NB_TOP.

wx.Notebook methods

integer GetRowCount()

get the number of rows

SetPadding(wx.Size padding)

set the amount of space around each page's icon and label

SetTabSize(wx.Size size)

set the tab size

(tab, where) HitTest(wx.Point point)

return the tab which is hit

wx.Size CalcSizeFromPage(wx.Size size)

something

add bookcontrolbase methods where return value of the

HitTest() method can be one of:

  • wx.NB_HITTEST_NOWHERE
  • wx.NB_HITTEST_ONITEM

In our example, we mimic the look of a spreadsheet.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # notebook.py
   4 
   5 import wx
   6 import wx.lib.sheet as sheet
   7 
   8 class MySheet(sheet.CSheet):
   9     def __init__(self, parent):
  10         sheet.CSheet.__init__(self, parent)
  11 
  12         self.SetLabelBackgroundColour('#DBD4D4')
  13         self.SetNumberRows(50)
  14         self.SetNumberCols(50)
  15 
  16 class Notebook(wx.Frame):
  17     def __init__(self, parent, id, title):
  18         wx.Frame.__init__(self, parent, id, title, size=(600, 500))
  19 
  20         menubar = wx.MenuBar()
  21         file = wx.Menu()
  22         file.Append(101, 'Quit', '' )
  23         menubar.Append(file, "&File")
  24         self.SetMenuBar(menubar)
  25         wx.EVT_MENU(self, 101, self.OnQuit)
  26         nb = wx.Notebook(self, -1, style=wx.NB_BOTTOM)
  27         self.sheet1 = MySheet(nb)
  28         self.sheet2 = MySheet(nb)
  29         self.sheet3 = MySheet(nb)
  30         nb.AddPage(self.sheet1, "Sheet1")
  31         nb.AddPage(self.sheet2, "Sheet2")
  32         nb.AddPage(self.sheet3, "Sheet3")
  33         self.sheet1.SetFocus()
  34         self.StatusBar()
  35 
  36     def StatusBar(self):
  37         self.statusbar = self.CreateStatusBar()
  38 
  39     def OnQuit(self, event):
  40         self.Close()
  41 
  42 class MyApp(wx.App):
  43     def OnInit(self):
  44          frame = Notebook(None, -1, 'notebook.py')
  45          frame.Show(True)
  46          frame.Centre()
  47          return True
  48 
  49 app = MyApp(0)
  50 app.MainLoop()

notebook.png

Figure: notebook.py

wx.lib Classes

Under lib directory we can find other widgets, improvements or extensions. Here we will show some more useful classes.

Mouse Gestures

We can find mouse gestures in such successfull applications like Firefox or Opera. They really help users save their time while browsing on the Interent. Mouse gestures are created with

wx.lib.gestures.MouseGestures class in wxPython.

Possible methods

AddGesture(string gesture, action)

registers a mouse gesture

RemoveGesture(string gesture)

removes a mouse gesture

SetGesturePen(wx.Colour colour, integer width)

sets the colour and width of the line drawn to visually represent each gesture

SetGesturesVisible(boolean vis)

sets wether a line is drawn to visually represent each gesture

SetWobbleTolerance(integer wobbletolerance)

sets the intensity to trigger a gesture

SetModifiers(list modifiers)

takes a list of wx.Key constants (Control, Shift, and/or Alt)

SetMouseButton(integer flag)

takes the wx constant for the target mousebutton

Available gestures:

  • L for left
  • R for right
  • U for up
  • D for down
  • 7 for northwest
  • 9 for northeast
  • 1 for southwest
  • 3 for southeast

If you wonder why these numbers were chosen, have a look at the numerical pad. Mouse gestures can be combined. This way 'RDLU' is a mouse gesture triggered, when we do a square with a mouse pointer.

Possible flags are:

  • wx.MOUSE_BTN_LEFT
  • wx.MOUSE_BTN_MIDDLE
  • wx.MOUSE_BTN_RIGHT

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # mousegestures.py
   4 
   5 import wx
   6 import wx.lib.gestures as gest
   7 
   8 class MyMouseGestures(wx.Frame):
   9     def __init__ (self, parent, id, title):
  10         wx.Frame.__init__(self, parent, id, title, size=(600, 500))
  11 
  12         panel = wx.Panel(self, -1)
  13         mg = gest.MouseGestures(panel, True, wx.MOUSE_BTN_LEFT)
  14         mg.SetGesturePen(wx.Colour(255, 0, 0), 2)
  15         mg.SetGesturesVisible(True)
  16         mg.AddGesture('DR', self.OnDownRight)
  17 
  18     def OnDownRight(self):
  19           self.Close()
  20 
  21 class MyApp(wx.App):
  22     def OnInit(self):
  23         frame = MyMouseGestures(None, -1, "mousegestures.py")
  24         frame.Show(True)
  25         frame.Centre()
  26         return True
  27 
  28 app = MyApp(0)
  29 app.MainLoop()

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.

mg.AddGesture('DR', self.OnDownRight)

AnalogClockWindow

Simple analog clock.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # analogclock.py
   4 
   5 import wx
   6 from wx.lib import analogclock as ac
   7 
   8 class MyFrame(wx.Frame):
   9     def __init__(self, parent, id, title):
  10         wx.Frame.__init__(self, parent, id, title)
  11 
  12         clock = ac.AnalogClockWindow(self)
  13         clock.SetBackgroundColour('gray')
  14         clock.SetHandColours('black')
  15         clock.SetTickColours('WHITE')
  16         clock.SetTickSizes(h=5, m=2)
  17         clock.SetTickStyles(ac.TICKS_ROMAN)
  18         self.SetSize((400,350))
  19 
  20 class MyApp(wx.App):
  21     def OnInit(self):
  22         frame = MyFrame(None, -1, 'analogclock.py')
  23         frame.Show(True)
  24         frame.Centre()
  25         return True
  26 
  27 app = MyApp(0)
  28 app.MainLoop()

Various clock styles:

SetClockStyle()

  • SHOW_QUARTERS_TICKS
  • SHOW_HOURS_TICKS
  • SHOW_MINUTES_TICKS
  • SHOW_HOURS_HAND
  • SHOW_MINUTES_HAND
  • SHOW_SECONDS_HAND
  • SHOW_SHADOWS
  • ROTATE_TICKS
  • OVERLAP_TICKS

Various ticks styles:

SetTickStyles()

  • TICKS_NONE
  • TICKS_SQUARE
  • TICKS_CIRCLE
  • TICKS_POLY
  • TICKS_DECIMAL
  • TICKS_ROMAN

analogclock.png

Figure: analogclock.py

Bitmap Text Buttons

We cannot use wx.Button class if we want to display text buttons with images. For this task, we have awx.GenBitmapTextButton class.

The constructor is:

wx.GenBitmapTextButton(parent, ID=-1, bitmap=wx.NullBitmap, label='', pos = wx.DefaultPosition, size = wx.DefaultSize,
                 style = 0, validator = wx.DefaultValidator, name = 'genbutton')

This class is found under wx.lib.buttons.

In our example we show a possible use for this class.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # genbitmaptextbutton.py
   4 
   5 import wx
   6 from wx.lib.buttons import GenBitmapTextButton
   7 
   8 class MyDialog(wx.Dialog):
   9     def __init__(self, parent, id, title):
  10         wx.Dialog.__init__(self, parent, id, title, size = (200, 220))
  11 
  12         panel = wx.Panel(self, -1)
  13         email = GenBitmapTextButton(self, 1, wx.Bitmap('email.png'), 'Mail', (25, 20), (150, -1))
  14         email.SetBezelWidth(1)
  15         email.SetBackgroundColour('#c2e6f8')
  16         calendar = GenBitmapTextButton(self, 2, wx.Bitmap('calendar.png'), 'Calendar', (25, 56), (150, -1))
  17         calendar.SetBezelWidth(1)
  18         calendar.SetBackgroundColour('#c2e6f8')
  19         contacts = GenBitmapTextButton(self, 3, wx.Bitmap('contacts.png'), 'Contacts', (25, 92), (150, -1))
  20         contacts.SetBezelWidth(1)
  21         contacts.SetBackgroundColour('#c2e6f8')
  22         tasks = GenBitmapTextButton(self, 4, wx.Bitmap('tasks.png'), 'Tasks', (25, 128), (150, -1))
  23         tasks.SetBezelWidth(1)
  24         tasks.SetBackgroundColour('#c2e6f8')
  25         notes = GenBitmapTextButton(self, 5, wx.Bitmap('notes.png'), 'Notes', (25, 164), (150, -1))
  26         notes.SetBezelWidth(1)
  27         notes.SetBackgroundColour('#c2e6f8')
  28 
  29         email.Bind(wx.EVT_ENTER_WINDOW, self.OnButtonEnter)
  30         email.Bind(wx.EVT_LEAVE_WINDOW, self.OnButtonLeave)
  31         calendar.Bind(wx.EVT_ENTER_WINDOW, self.OnButtonEnter)
  32         calendar.Bind(wx.EVT_LEAVE_WINDOW, self.OnButtonLeave)
  33         contacts.Bind(wx.EVT_ENTER_WINDOW, self.OnButtonEnter)
  34         contacts.Bind(wx.EVT_LEAVE_WINDOW, self.OnButtonLeave)
  35         tasks.Bind(wx.EVT_ENTER_WINDOW, self.OnButtonEnter)
  36         tasks.Bind(wx.EVT_LEAVE_WINDOW, self.OnButtonLeave)
  37         notes.Bind(wx.EVT_ENTER_WINDOW, self.OnButtonEnter)
  38         notes.Bind(wx.EVT_LEAVE_WINDOW, self.OnButtonLeave)
  39 
  40         self.Centre()
  41 
  42     def OnButtonEnter(self, event):
  43         obj =  event.GetEventObject()
  44         obj.SetBackgroundColour('#ffdf85')
  45         obj.Refresh()
  46 
  47     def OnButtonLeave(self, event):
  48         obj =  event.GetEventObject()
  49         obj.SetBackgroundColour('#c2e6f8')
  50         obj.Refresh()
  51 
  52 class MyApp(wx.App):
  53     def OnInit(self):
  54         dlg = MyDialog(None, -1, 'gentextbitmapbutton.py')
  55         dlg.ShowModal()
  56         dlg.Destroy()
  57         return True
  58 
  59 app = MyApp(0)
  60 app.MainLoop()

genbitmaptextbutton.png

Figure: genbitmaptextbutton.py

Advanced Widgets

In this section we will discuss some advanced widgets. They are found in lib subdirectory which is in wx directory. These widgets are written in python. They address needs not covered by the underlying C++ wx library.

CalendarCtrl

CalendarCtrl is a handy widget for working with dates.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # calendar.py
   4 
   5 import wx
   6 import wx.calendar as cal
   7 
   8 class Calendar(wx.Dialog):
   9     def __init__(self, parent, id, title):
  10         wx.Dialog.__init__(self, parent, id, title)
  11 
  12         vbox = wx.BoxSizer(wx.VERTICAL)
  13 
  14         calend = cal.CalendarCtrl(self, -1, wx.DateTime_Now(),
  15             style = cal.CAL_SHOW_HOLIDAYS|cal.CAL_SEQUENTIAL_MONTH_SELECTION)
  16         vbox.Add(calend, 0, wx.EXPAND | wx.ALL, 20)
  17         self.Bind(cal.EVT_CALENDAR, self.OnCalSelected, id=calend.GetId())
  18 
  19         vbox.Add((-1, 20))
  20 
  21         hbox = wx.BoxSizer(wx.HORIZONTAL)
  22         self.text = wx.StaticText(self, -1, 'Date')
  23         hbox.Add(self.text)
  24         vbox.Add(hbox, 0,  wx.LEFT, 8)
  25 
  26         hbox2 = wx.BoxSizer(wx.HORIZONTAL)
  27         btn = wx.Button(self, -1, 'Ok')
  28         hbox2.Add(btn, 1)
  29         vbox.Add(hbox2, 0, wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, 20)
  30 
  31         self.Bind(wx.EVT_BUTTON, self.OnQuit, id=btn.GetId())
  32         self.Bind(wx.EVT_CLOSE, self.OnQuit)
  33 
  34         self.SetSizerAndFit(vbox)
  35 
  36         self.Show(True)
  37         self.Centre()
  38 
  39 
  40     def OnCalSelected(self, event):
  41         date = event.GetDate()
  42         dt = str(date).split(' ')
  43         s = ' '.join(str(s) for s in dt)
  44         self.text.SetLabel(s)
  45 
  46     def OnQuit(self, event):
  47         self.Destroy()
  48 
  49 
  50 app = wx.App()
  51 Calendar(None, -1, 'calendar.py')
  52 app.MainLoop()

Possible calendar styles:

Listed below.

calendar.png

Figure: calendar.py

LEDNumberCtrl

In the previous example we had an analog clock example.LEDNumberCtrl widget displays a digital clock.

In our example we show current local time in a simple wx.Frame.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # lednumber.py
   4 
   5 import time
   6 import wx
   7 import wx.gizmos as gizmos
   8 
   9 class MyFrame(wx.Frame):
  10     def __init__(self, parent, id, title):
  11         wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(450, 100))
  12 
  13         self.led = gizmos.LEDNumberCtrl(self, -1, wx.DefaultPosition, wx.DefaultSize, gizmos.LED_ALIGN_CENTER)
  14         self.OnTimer(None)
  15         self.timer = wx.Timer(self, -1)
  16         self.timer.Start(1000)
  17         self.Bind(wx.EVT_TIMER, self.OnTimer)
  18         self.Centre()
  19 
  20     def OnTimer(self, event):
  21         t = time.localtime(time.time())
  22         st = time.strftime("%I:%M:%S", t)
  23         self.led.SetValue(st)
  24 
  25 class MyApp(wx.App):
  26     def OnInit(self):
  27         frame = MyFrame(None, -1, 'lednumber.py')
  28         frame.Show(True)
  29         self.SetTopWindow(frame)
  30         return True
  31 
  32 app = MyApp(0)
  33 app.MainLoop()

Possible flags:

  • LED_ALIGN_LEFT
  • LED_ALIGN_RIGHT
  • LED_ALIGN_CENTER
  • LED_ALIGN_MASK
  • LED_DRAW_FADED

Windows users, putwx.CallAfter() in your code:

self.led = gizmos.LEDNumberCtrl(self, -1, style=gizmos.LED_ALIGN_CENTER)
wx.CallAfter(self.OnTimer, None)
self.timer = wx.Timer(self, -1)

lednumber.png

Figure: lednumber.py

Creating a taskbar application

Some applications are placed on a taskbar. It is an area on a panel usually at the right bottom of the screen. They are represented by a small icon. They are specialized programs designed to do some specific task. Common examples are a clock, sound mixer, language switcher. They are also called applets. In wxPython we have a

wx.TaskbarIcon class for creating such applets. The constructor does not take any parameters.

wx.TaskbarIcon()

Available methods

Destroy()

destroys a taskbaricon object

SetIcon(wx.Icon icon, string tooltip)

sets an icon with optional tooltip

IsIconInstalled()

checks if the icon is set

IsOk()

checks if the object is created

RemoveIcon()

removes the icon

PopupMenu(wx.Menu menu)

pops up a menu

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # mytaskbaricon.py
   4 
   5 import wx
   6 
   7 class MyTaskBarIcon(wx.TaskBarIcon):
   8     def __init__(self, frame):
   9         wx.TaskBarIcon.__init__(self)
  10 
  11         self.frame = frame
  12         self.SetIcon(wx.Icon('web.png', wx.BITMAP_TYPE_PNG), 'mytaskbaricon.py')
  13         self.Bind(wx.EVT_MENU, self.OnTaskBarActivate, id=1)
  14         self.Bind(wx.EVT_MENU, self.OnTaskBarDeactivate, id=2)
  15         self.Bind(wx.EVT_MENU, self.OnTaskBarClose, id=3)
  16 
  17     def CreatePopupMenu(self):
  18         menu = wx.Menu()
  19         menu.Append(1, 'Show')
  20         menu.Append(2, 'Hide')
  21         menu.Append(3, 'Close')
  22         return menu
  23 
  24     def OnTaskBarClose(self, event):
  25         self.frame.Close()
  26 
  27     def OnTaskBarActivate(self, event):
  28         if not self.frame.IsShown():
  29             self.frame.Show()
  30 
  31     def OnTaskBarDeactivate(self, event):
  32         if self.frame.IsShown():
  33             self.frame.Hide()
  34 
  35 class MyFrame(wx.Frame):
  36     def __init__(self, parent, id, title):
  37         wx.Frame.__init__(self, parent, id, title, (-1, -1), (290, 280))
  38 
  39         self.tskic = MyTaskBarIcon(self)
  40         self.Centre()
  41         self.Bind(wx.EVT_CLOSE, self.OnClose)
  42 
  43     def OnClose(self, event):
  44         self.tskic.Destroy()
  45         self.Destroy()
  46 
  47 class MyApp(wx.App):
  48     def OnInit(self):
  49         frame = MyFrame(None, -1, 'mytaskbaricon.py')
  50         frame.Show(True)
  51         self.SetTopWindow(frame)
  52         return True
  53 
  54 app = MyApp(0)
  55 app.MainLoop()

taskbaricon.png

Figure: mytaskbaricon.py

wx.TheClipboard

From wikipedia:

In computing, the clipboard is a portion of memory where information that has been copied or cut from a computer application is stored. This storage is meant as a short-term volatile place to keep information that will be used again shortly.

wx.TheClipboard is a class for manipulating clipboard in wxPython. Fist we must call the Open() method to get ownership of the clipboard. If successful, the method returns true. Then we put data on the clipboard with the

SetData() method. This method accepts a simple data object.

We have three predefined simple data objects:

  • wx.FileDataObject

  • wx.TextDataObject

  • wx.BitmapDataObject

To retrieve data from Clipboard you call methodGetData(). It accepts simple data object as well. In the end we close the clipboard with Close() method and relinquish ownership of it.

clipboard.py example shows a simple usage of the the clipboard in wxPython.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # clipboard.py
   4 
   5 import wx
   6 
   7 class MyFrame(wx.Frame):
   8     def __init__(self, parent, id, title):
   9         wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(320, 300))
  10 
  11         panel1 = wx.Panel(self, -1)
  12         self.tc1 = wx.TextCtrl(panel1, -1, '', (50,50), (85, -1))
  13         self.tc2 = wx.TextCtrl(panel1, -1, '', (180,50), (85, -1))
  14         wx.Button(panel1, 1, 'Copy', (50,200))
  15         wx.Button(panel1, 2, 'Paste', (180,200))
  16         self.Bind(wx.EVT_BUTTON, self.OnCopy, id=1)
  17         self.Bind(wx.EVT_BUTTON, self.OnPaste, id=2)
  18         self.Centre()
  19 
  20     def OnCopy(self, event):
  21         text = self.tc1.GetValue()
  22         if wx.TheClipboard.Open():
  23             wx.TheClipboard.Clear()
  24             wx.TheClipboard.SetData(wx.TextDataObject(text))
  25             wx.TheClipboard.Close()
  26 
  27     def OnPaste(self, event):
  28         if wx.TheClipboard.Open():
  29             td = wx.TextDataObject()
  30             success = wx.TheClipboard.GetData(td)
  31             wx.TheClipboard.Close()
  32             if not success: return
  33             text = td.GetText()
  34             if text: self.tc2.SetValue(text)
  35 
  36 class MyApp(wx.App):
  37     def OnInit(self):
  38         frame = MyFrame(None, -1, 'clipboard.py')
  39         frame.Show(True)
  40         self.SetTopWindow(frame)
  41         return True
  42 
  43 app = MyApp(0)
  44 app.MainLoop()

We have two textcontrols and two buttons. We input some text into the first textcontrol and paste in the the second one with our two buttons. Notice how we retrieve data from thewxTextDataObject:

text = td.GetText()

Drag and Drop

Wikipedia:

In computer graphical user interfaces, drag-and-drop is the action of (or support for the action of) clicking on a virtual object and dragging it to a different location or onto another virtual object. In general, it can be used to invoke many kinds of actions, or create various types of associations between two abstract objects. I think everyone is familiar with drag

& drop. Here is an example in wxPython:

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # dragdrop.py
   4 
   5 import os
   6 import wx
   7 
   8 class MyTextDropTarget(wx.TextDropTarget):
   9     def __init__(self, object):
  10         wx.TextDropTarget.__init__(self)
  11         self.object = object
  12 
  13     def OnDropText(self, x, y, data):
  14         self.object.InsertStringItem(0, data)
  15 
  16 class MyFrame(wx.Frame):
  17     def __init__(self, parent, id, title):
  18         wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(450, 400))
  19 
  20         splitter1 = wx.SplitterWindow(self, -1, style=wx.SP_3D)
  21         splitter2 = wx.SplitterWindow(splitter1, -1, style=wx.SP_3D)
  22         self.dir = wx.GenericDirCtrl(splitter1, -1, dir='/home/', style=wx.DIRCTRL_DIR_ONLY)
  23         self.lc1 = wx.ListCtrl(splitter2, -1, style=wx.LC_LIST)
  24         self.lc2 = wx.ListCtrl(splitter2, -1, style=wx.LC_LIST)
  25         dt = MyTextDropTarget(self.lc2)
  26         self.lc2.SetDropTarget(dt)
  27         wx.EVT_LIST_BEGIN_DRAG(self, self.lc1.GetId(), self.OnDragInit)
  28         tree = self.dir.GetTreeCtrl()
  29         splitter2.SplitHorizontally(self.lc1, self.lc2)
  30         splitter1.SplitVertically(self.dir, splitter2)
  31         wx.EVT_TREE_SEL_CHANGED(self, tree.GetId(), self.OnSelect)
  32         self.OnSelect(0)
  33         self.Centre()
  34 
  35     def OnSelect(self, event):
  36         list = os.listdir(self.dir.GetPath())
  37         self.lc1.ClearAll()
  38         self.lc2.ClearAll()
  39         for i in range(len(list)):
  40             if list[i][0] != '.':
  41                 self.lc1.InsertStringItem(0, list[i])
  42 
  43     def OnDragInit(self, event):
  44         text = self.lc1.GetItemText(event.GetIndex())
  45         tdo = wx.PyTextDataObject(text)
  46         tds = wx.DropSource(self.lc1)
  47         tds.SetData(tdo)
  48         tds.DoDragDrop(True)
  49 
  50 class MyApp(wx.App):
  51     def OnInit(self):
  52         frame = MyFrame(None, -1, "dragdrop.py")
  53         frame.Show(True)
  54         self.SetTopWindow(frame)
  55         return True
  56 
  57 app = MyApp(0)
  58 app.MainLoop()

dragdrop.png

Figure: dragdrop.py

One of the advantages of the GUI over the console is it's intuitiveness. You can learn a GUI program easier than a console application. You often do not need a manual. On the other hand, some graphical operations are too complex. For example, deleting a file by dragging it and droping it to the trash basket is very intuitive and easy to understand, but actually most people just press the delete key. (shift + delete) It is more effective. In our next example we explore a graphical operation, that is very handy. In most GUI text editors, you can open a file by simply dragging it from the file manager and dropping it on the editor.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # filedrop.py
   4 
   5 import wx
   6 
   7 class FileDrop(wx.FileDropTarget):
   8     def __init__(self, window):
   9         wx.FileDropTarget.__init__(self)
  10         self.window = window
  11 
  12     def OnDropFiles(self, x, y, filenames):
  13 
  14         for name in filenames:
  15             try:
  16                 file = open(name, 'r')
  17                 text = file.read()
  18                 self.window.WriteText(text)
  19                 file.close()
  20             except IOError, error:
  21                 dlg = wx.MessageDialog(None, 'Error opening file\n' + str(error))
  22                 dlg.ShowModal()
  23             except UnicodeDecodeError, error:
  24                 dlg = wx.MessageDialog(None, 'Cannot open non ascii files\n' + str(error))
  25                 dlg.ShowModal()
  26 
  27 class MyFrame(wx.Frame):
  28     def __init__(self, parent, id, title):
  29         wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(450, 400))
  30         self.text = wx.TextCtrl(self, -1, style = wx.TE_MULTILINE)
  31         dt = FileDrop(self.text)
  32         self.text.SetDropTarget(dt)
  33         self.Centre()
  34 
  35 class MyApp(wx.App):
  36     def OnInit(self):
  37         frame = MyFrame(None, -1, '')
  38         frame.Show(True)
  39         self.SetTopWindow(frame)
  40         return True
  41 
  42 app = MyApp(0)
  43 app.MainLoop()

Plotting

wxPython comes with a simple plotting library. Features include zooming, legends and a grid.

Possible graphs:

  • scatter
  • line
  • bar

We must install the Numeric library. Other plotting libraries are

Gnuplot or MatPlotLib. These must be installed separately.

To create a graph, we follow these steps:

1) Define our data

we insert your data in a list of tuples. Each tuple will have two items.

data = [(x1, y1), (x2, y2), (x3, y3), (x4, y4), (x5, y5), (x6, y6)]

2) Create a plotting canvas we create an object of a

PlotCanvas as a child of a frame.

   frame = wx.Frame(self, -1)
   client = wx.lib.plot.PlotCanvas(frame)

3) Create a graph There are two classes.

PolyLine and PolyMarker. PolyLine class defines line graphs. It's constructor is:

PolyLine(list data, wx.Colour colour, integer width, integer style, string legend)

data parameter is the data to be displayed. colour defines the colour of the line. width is the width of the pen, used to draw the graph. possible style flags are wx.Pen stylesare listed below. legend defines the line legend.

PolyMarker can be used to create scatter graphs and bar graphs as well. Constructor:

PolyMarker(list data, wx.Colour colour, integer size, wx.Colour fillcolour, integer fillstyle, string markershape, string legend)

fillstyle is also various wx.Pen styles.

Marker Shapes:

  • circle
  • dot
  • square
  • triangle
  • triangle_down
  • cross
  • plus

4) Create a graph container

Graph container is a container that holds a graph object and it's title and labels.

PlotGraphics(list objects, string title, string xLabel, string yLabel)
  • objects is a list of one or more graph objects
  • title - title shown at top of graph
  • xLabel - label shown on x-axis
  • yLabel - label shown on y-axis

5) Draw a graph

finally we draw the graph.

client.Draw(gc,  xAxis=(0,15), yAxis=(0,15))

gc is a graph container object. xAxis and yAxis define the range of the axes

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # plot.py
   4 
   5 import wx
   6 import wx.lib.plot as plot
   7 
   8 class Plot(wx.Dialog):
   9         def __init__(self, parent, id, title):
  10                 wx.Dialog.__init__(self, parent, id, title, size=(180, 280))
  11 
  12                 self.data = [(1,2), (2,3), (3,5), (4,6), (5,8), (6,8), (10,10)]
  13                 btn1 = wx.Button(self,  1, 'scatter', (50,50))
  14                 btn2 = wx.Button(self,  2, 'line', (50,90))
  15                 btn3 = wx.Button(self,  3, 'bar', (50,130))
  16                 btn4 = wx.Button(self,  4, 'quit', (50,170))
  17                 wx.EVT_BUTTON(self, 1, self.OnScatter)
  18                 wx.EVT_BUTTON(self, 2, self.OnLine)
  19                 wx.EVT_BUTTON(self, 3, self.OnBar)
  20                 wx.EVT_BUTTON(self, 4, self.OnQuit)
  21                 wx.EVT_CLOSE(self, self.OnQuit)
  22 
  23         def OnScatter(self, event):
  24                 frm = wx.Frame(self, -1, 'scatter', size=(600,450))
  25                 client = plot.PlotCanvas(frm)
  26                 markers = plot.PolyMarker(self.data, legend='', colour='pink', marker='triangle_down', size=1)
  27                 gc = plot.PlotGraphics([markers], 'Scatter Graph', 'X Axis', 'Y Axis')
  28                 client.Draw(gc, xAxis=(0,15), yAxis=(0,15))
  29                 frm.Show(True)
  30 
  31         def OnLine(self, event):
  32                 frm = wx.Frame(self, -1, 'line', size=(600,450))
  33                 client = plot.PlotCanvas(frm)
  34                 line = plot.PolyLine(self.data, legend='', colour='pink', width=1)
  35                 gc = plot.PlotGraphics([line], 'Line Graph', 'X Axis', 'Y Axis')
  36                 client.Draw(gc,  xAxis= (0,15), yAxis= (0,15))
  37                 frm.Show(True)
  38 
  39         def OnBar(self, event):
  40                 frm = wx.Frame(self, -1, 'bar', size=(600,450))
  41                 client = plot.PlotCanvas(frm)
  42                 bar1 = plot.PolyLine([(1, 0), (1,5)], legend='', colour='gray', width=25)
  43                 bar2 = plot.PolyLine([(3, 0), (3,8)], legend='', colour='gray', width=25)
  44                 bar3 = plot.PolyLine([(5, 0), (5,12)], legend='', colour='gray', width=25)
  45                 bar4 = plot.PolyLine([(6, 0), (6,2)], legend='', colour='gray', width=25)
  46                 gc = plot.PlotGraphics([bar1, bar2, bar3, bar4],'Bar Graph', 'X Axis', 'Y Axis')
  47                 client.Draw(gc, xAxis=(0,15), yAxis=(0,15))
  48                 frm.Show(True)
  49 
  50         def OnQuit(self, event):
  51                 self.Destroy()
  52 
  53 class MyApp(wx.App):
  54        def OnInit(self):
  55                  dlg = Plot(None, -1, 'plot.py')
  56                  dlg.Show(True)
  57                  dlg.Centre()
  58                  return True
  59 app = MyApp(0)
  60 app.MainLoop()

scattergraph.png linegraph.png bargraph.png

Figures: scatter, line, bar graphs

Configuring application settings

Many applications allow users to configure their settings. Users can toggle tooltips on and of, change fonts, default download paths etc. Mostly they have a menu option called preferences. Application settings are saved to the hard disk, so that users do not have to change the settings each time the application starts.

In wxPython we have wx.Config class to do our job.

On Linux, settings are stored in a simple hidden file. This file is located in the home user directory by default. The location of the configuration file can be changed. The name of the file is specified in the constructor of the wx.Config class.

Various wx.Config methods

string Read(string key, string defaultVal='')

return a string value of a key if it exists, defaultVal otherwise

int ReadInt(string key, int defaultVal=0)

return an integer value of the key if it exists, defaultVal otherwise

float ReadFloat(string key, float defaultVal=0.0)

return a float value of a key if it exists, defaultVal otherwise

bool ReadBool(string key, bool defaultVal=False)

return a boolean value of a key if it exists, defaultVal otherwise

bool Write(string key, string value)

write a string value, return True on success

bool WriteInt(string key, int value)

write an integer value, return True on success

bool WriteFloat(string key, float value)

write a float value, return True on success

bool WriteBool(string key, bool value)

write a boolean value, return True on success

bool Exists(string value)

return True if a key with a given name exists

In the following code example, we can cofigure the size of the window. If there is no configuration file, the height and the width of the window is set to the defaul 250 px value. We can set these values to a range from 200 - 500px. After we save our values and restart the application, the window size is set to our preffered values.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # myconfig.py
   4 
   5 import wx
   6 
   7 class MyFrame(wx.Frame):
   8     def __init__(self, parent, id, title):
   9         self.cfg = wx.Config('myconfig')
  10         if self.cfg.Exists('width'):
  11             w, h = self.cfg.ReadInt('width'), self.cfg.ReadInt('height')
  12         else:
  13             (w, h) = (250, 250)
  14         wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(w, h))
  15 
  16         wx.StaticText(self, -1, 'Width:', (20, 20))
  17         wx.StaticText(self, -1, 'Height:', (20, 70))
  18         self.sc1 = wx.SpinCtrl(self, -1, str(w), (80, 15), (60, -1), min=200, max=500)
  19         self.sc2 = wx.SpinCtrl(self, -1, str(h), (80, 65), (60, -1), min=200, max=500)
  20         wx.Button(self, 1, 'Save', (20, 120))
  21 
  22         self.Bind(wx.EVT_BUTTON, self.OnSave, id=1)
  23         self.statusbar = self.CreateStatusBar()
  24         self.Centre()
  25 
  26     def OnSave(self, event):
  27         self.cfg.WriteInt("width", self.sc1.GetValue())
  28         self.cfg.WriteInt("height", self.sc2.GetValue())
  29         self.statusbar.SetStatusText('Configuration saved, %s ' % wx.Now())
  30 
  31 
  32 class MyApp(wx.App):
  33     def OnInit(self):
  34         frame = MyFrame(None, -1, 'myconfig.py')
  35         frame.Show(True)
  36         self.SetTopWindow(frame)
  37         return True
  38 
  39 app = MyApp(0)
  40 app.MainLoop()

Here we have the contents of a configuration file to our code example . It consists of two key, value pairs.

$ cat .myconfig
height=220
width=340

myconfig.png

Figure: myconfig.py

wxPython functions

wxPython provides several useful functions. We can implement them easily in our programs. Technically, these functions are module functions. e.g defined in a module scope. They resemble what we know as static methods in C++ or Java.

System functions

System functions

wx.Bell()

beep a sound

wx.GetDisplaySize()

return the current display mode

wx.GetEmailAddress()

return user's email address

wx.GetFullHostName()

return full host name

wx.GetHomeDir()

return the user's home direstory

wx.GetOsVersion()

return Os version

wx.GetOsDescription()

return a full Os description

wx.GetFreeMemory()

not working

wx.GetMousePosition()

return mouse position

wx.GetProcessId()

return a process id of our application

wx.GetUserName()

returns a user's name

wx.GetUTCTime()

return number of seconds

wx.Now()

return current timestamp

wx.Shell(string command)

execute a command in a shell

Dialog functions

These functions create dialogs. They do some common tasks.

Dialog functions

wx.GetTextFromUser()

get a text from user

wx.DirSelector()

select a directory

wx.FileSelector()

select a file

wx.GetNumberFromUser()

get a long number from user

wx.GetSingleChoice()

something

wx.GetSingleChoiceIndex()

something

wx.GetSingleChoiceIndex()

something

wx.LoadFileSelector()

load a file

wx.MessageBox()

show a message dialog

wx.SaveFileSelector()

saves a file

string wx.GetTextFromUser(string message, string caption='', string default_value='', wx.Window parent=None)
string wx.DirSelector(string message=wx.DirSelectorPromptStr, string defaultPath='', style=wx.DD_DEFAULT_STYLE,
                      wx.Point pos=wx.DefaultPosition, wx.Window parent=None)
string wx.FileSelector(string message=wx.FileSelectorPromptStr, string default_path='', string default_filename='',
                       string default_extension='', string wildcard=wx.FileSelectorDefaultWildcardStr,
                       integer flags=0, wx.Window parent=None, integer x=-1, integer y=-1)
long wx.GetNumberFromUser(string message, string prompt, string caption, long value, long min=0, long max=100,
                          wx.Window parent=None, wx.Point pos=wx.DefaultPosition)
string wx.GetSingleChoice(string message, string caption, integer choices, string choices_array,
                          wx.Window parent=None, integer x=-1, integer y=-1, bool centre=True, integer width=150,
                          integer height=200)
integer wx.GetSingleChoiceIndex(string message, string caption, integer choices, string choices_array,
                                wx.Window parent=None, integer x=-1, integer y=-1, bool centre=True,
                                integer width=150, integer height=200)
string wx.LoadFileSelector(string what, string extension, string default_name='', wx.Window parent=None)
integer wx.MessageBox(string message, string caption='', style=wx.OK | wx.CENTRE, wx.Window parent=None,
                      integer x=-1, integer y=-1)
string wx.SaveFileSelector(string what, string extension, string default_name='', wx.Window parent=None)

Other functions

Here is a list of various other functions

Other functions

wx.Exit()

exit application

bool wx.Yield()

yield to other applications or messages

bool wx.YieldIfNeeded()

something

bool SafeYield(wx.Window window=None, bool onlyIfNeeded=False)

something

wx.WakeUpIdle()

empty the message queue

wx.PostEvent(wx.EvtHandler dest, wx.Event event)

wx.EventHandler to be processed later

PyApp wx.GetApp()

return a reference to the current wx.App object

wx.SetDefaultPyEncoding(string encoding)

set the current encoding for working with wx.String

string wx.GetDefaultPyEncoding()

get the current encoding for working with wx.String

Using xml resource files

The idea behind xml resources is to separate the interface from the code of an application. Several GUI builders use this concept for creating interfaces. For example the famous Glade.

In our example we create a simple frame window with one button. We load resources from a file, load a panel and bind an event to a button.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # xml.py
   4 
   5 import  wx
   6 import  wx.xrc  as  xrc
   7 
   8 class Xml(wx.Frame):
   9     def __init__(self, parent, id, title):
  10         wx.Frame.__init__(self, parent, id, title)
  11 
  12         res = xrc.XmlResource('resource.xrc')
  13         res.LoadPanel(self, 'MyPanel')
  14 
  15         self.Bind(wx.EVT_BUTTON, self.OnClose,  id=xrc.XRCID('CloseButton'))
  16         self.Center()
  17         self.Show(True)
  18 
  19 
  20     def OnClose(self, event):
  21         self.Close()
  22 
  23 app = wx.App()
  24 Xml(None, -1, 'xml.py')
  25 app.MainLoop()

This is resource file resource.xrc It is a xml file, where we define our widgets and their patterns. In this file, we use tags like<object></object>, <item></item> etc.

<?xml version="1.0" ?>
<resource>
  <object class="wxPanel" name="MyPanel">
   <object class="wxButton" name="CloseButton">
    <label>Close</label>
    <pos>150,100</pos>
   </object>
  </object>
</resource>

We use these two calls for working with widgets:

  • XRCID(resource_name) - gives us the id of a button or menu item
  • XRCCTRL(resource_name) - gives us the handlers of our widgets defined in resource file

Skeletons

In this section, we will create some application skeletons. Our scripts will work out the interface but will not implement the functionality. The goal is to show, how several well known GUI interfaces could be done in wxPython. Most manuals, tutorials and books show only the basic usage of a widget. When I was a beginner, I always wondered how this or this could be done. And I think, many newbies think the same.

File Hunter

File Hunter is a skeleton of a file manager. It copies the lookout of the Krusader, the best file manager available on Unix systems.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 import wx
   4 import os
   5 import time
   6 
   7 
   8 ID_BUTTON=100
   9 ID_EXIT=200
  10 ID_SPLITTER=300
  11 
  12 class MyListCtrl(wx.ListCtrl):
  13     def __init__(self, parent, id):
  14         wx.ListCtrl.__init__(self, parent, id, style=wx.LC_REPORT)
  15 
  16         files = os.listdir('.')
  17         images = ['images/empty.png', 'images/folder.png', 'images/source_py.png', 'images/image.png', 'images/pdf.png', 'images/up16.png']
  18 
  19         self.InsertColumn(0, 'Name')
  20         self.InsertColumn(1, 'Ext')
  21         self.InsertColumn(2, 'Size', wx.LIST_FORMAT_RIGHT)
  22         self.InsertColumn(3, 'Modified')
  23 
  24         self.SetColumnWidth(0, 220)
  25         self.SetColumnWidth(1, 70)
  26         self.SetColumnWidth(2, 100)
  27         self.SetColumnWidth(3, 420)
  28 
  29         self.il = wx.ImageList(16, 16)
  30         for i in images:
  31             self.il.Add(wx.Bitmap(i))
  32         self.SetImageList(self.il, wx.IMAGE_LIST_SMALL)
  33 
  34         j = 1
  35         self.InsertStringItem(0, '..')
  36         self.SetItemImage(0, 5)
  37 
  38         for i in files:
  39             (name, ext) = os.path.splitext(i)
  40             ex = ext[1:]
  41             size = os.path.getsize(i)
  42             sec = os.path.getmtime(i)
  43             self.InsertStringItem(j, name)
  44             self.SetStringItem(j, 1, ex)
  45             self.SetStringItem(j, 2, str(size) + ' B')
  46             self.SetStringItem(j, 3, time.strftime('%Y-%m-%d %H:%M', time.localtime(sec)))
  47 
  48             if os.path.isdir(i):
  49                 self.SetItemImage(j, 1)
  50             elif ex == 'py':
  51                 self.SetItemImage(j, 2)
  52             elif ex == 'jpg':
  53                 self.SetItemImage(j, 3)
  54             elif ex == 'pdf':
  55                 self.SetItemImage(j, 4)
  56             else:
  57                 self.SetItemImage(j, 0)
  58 
  59             if (j % 2) == 0:
  60                 self.SetItemBackgroundColour(j, '#e6f1f5')
  61             j += 1
  62 
  63 class FileHunter(wx.Frame):
  64     def __init__(self, parent, id, title):
  65         wx.Frame.__init__(self, parent, -1, title)
  66 
  67         self.splitter = wx.SplitterWindow(self, ID_SPLITTER, style=wx.SP_BORDER)
  68         self.splitter.SetMinimumPaneSize(50)
  69 
  70         p1 = MyListCtrl(self.splitter, -1)
  71         p2 = MyListCtrl(self.splitter, -1)
  72         self.splitter.SplitVertically(p1, p2)
  73 
  74         self.Bind(wx.EVT_SIZE, self.OnSize)
  75         self.Bind(wx.EVT_SPLITTER_DCLICK, self.OnDoubleClick, id=ID_SPLITTER)
  76 
  77         filemenu= wx.Menu()
  78         filemenu.Append(ID_EXIT,"E&xit"," Terminate the program")
  79         editmenu = wx.Menu()
  80         netmenu = wx.Menu()
  81         showmenu = wx.Menu()
  82         configmenu = wx.Menu()
  83         helpmenu = wx.Menu()
  84 
  85         menuBar = wx.MenuBar()
  86         menuBar.Append(filemenu,"&File")
  87         menuBar.Append(editmenu, "&Edit")
  88         menuBar.Append(netmenu, "&Net")
  89         menuBar.Append(showmenu, "&Show")
  90         menuBar.Append(configmenu, "&Config")
  91         menuBar.Append(helpmenu, "&Help")
  92         self.SetMenuBar(menuBar)
  93         self.Bind(wx.EVT_MENU, self.OnExit, id=ID_EXIT)
  94 
  95         tb = self.CreateToolBar( wx.TB_HORIZONTAL | wx.NO_BORDER | wx.TB_FLAT | wx.TB_TEXT)
  96         tb.AddSimpleTool(10, wx.Bitmap('images/previous.png'), 'Previous')
  97         tb.AddSimpleTool(20, wx.Bitmap('images/up.png'), 'Up one directory')
  98         tb.AddSimpleTool(30, wx.Bitmap('images/home.png'), 'Home')
  99         tb.AddSimpleTool(40, wx.Bitmap('images/refresh.png'), 'Refresh')
 100         tb.AddSeparator()
 101         tb.AddSimpleTool(50, wx.Bitmap('images/write.png'), 'Editor')
 102         tb.AddSimpleTool(60, wx.Bitmap('images/terminal.png'), 'Terminal')
 103         tb.AddSeparator()
 104         tb.AddSimpleTool(70, wx.Bitmap('images/help.png'), 'Help')
 105         tb.Realize()
 106 
 107         self.sizer2 = wx.BoxSizer(wx.HORIZONTAL)
 108 
 109         button1 = wx.Button(self, ID_BUTTON + 1, "F3 View")
 110         button2 = wx.Button(self, ID_BUTTON + 2, "F4 Edit")
 111         button3 = wx.Button(self, ID_BUTTON + 3, "F5 Copy")
 112         button4 = wx.Button(self, ID_BUTTON + 4, "F6 Move")
 113         button5 = wx.Button(self, ID_BUTTON + 5, "F7 Mkdir")
 114         button6 = wx.Button(self, ID_BUTTON + 6, "F8 Delete")
 115         button7 = wx.Button(self, ID_BUTTON + 7, "F9 Rename")
 116         button8 = wx.Button(self, ID_EXIT, "F10 Quit")
 117 
 118         self.sizer2.Add(button1, 1, wx.EXPAND)
 119         self.sizer2.Add(button2, 1, wx.EXPAND)
 120         self.sizer2.Add(button3, 1, wx.EXPAND)
 121         self.sizer2.Add(button4, 1, wx.EXPAND)
 122         self.sizer2.Add(button5, 1, wx.EXPAND)
 123         self.sizer2.Add(button6, 1, wx.EXPAND)
 124         self.sizer2.Add(button7, 1, wx.EXPAND)
 125         self.sizer2.Add(button8, 1, wx.EXPAND)
 126 
 127         self.Bind(wx.EVT_BUTTON, self.OnExit, id=ID_EXIT)
 128 
 129         self.sizer = wx.BoxSizer(wx.VERTICAL)
 130         self.sizer.Add(self.splitter,1,wx.EXPAND)
 131         self.sizer.Add(self.sizer2,0,wx.EXPAND)
 132         self.SetSizer(self.sizer)
 133 
 134         size = wx.DisplaySize()
 135         self.SetSize(size)
 136 
 137         self.sb = self.CreateStatusBar()
 138         self.sb.SetStatusText(os.getcwd())
 139         self.Center()
 140         self.Show(True)
 141 
 142 
 143     def OnExit(self,e):
 144         self.Close(True)
 145 
 146     def OnSize(self, event):
 147         size = self.GetSize()
 148         self.splitter.SetSashPosition(size.x / 2)
 149         self.sb.SetStatusText(os.getcwd())
 150         event.Skip()
 151 
 152 
 153     def OnDoubleClick(self, event):
 154         size =  self.GetSize()
 155         self.splitter.SetSashPosition(size.x / 2)
 156 
 157 app = wx.App(0)
 158 filehunter = FileHunter(None, -1, 'File Hunter')
 159 app.MainLoop()

If you double click on the splitter widget, it will divide the File Hunter into two parts with the same width. The same happens, if you resize the main window.

filehunter.png

Figure: File Hunter

SpreadSheet

Gnumeric, KSpread andOpenOffice Calc are famous spreadsheet applications available on Unix. The following example shows a skeleton of a spreadsheet application in wxPython.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # spreadsheet.py
   4 
   5 from wx.lib import sheet
   6 import wx
   7 
   8 
   9 class MySheet(sheet.CSheet):
  10     def __init__(self, parent):
  11         sheet.CSheet.__init__(self, parent)
  12         self.row = self.col = 0
  13         self.SetNumberRows(55)
  14         self.SetNumberCols(25)
  15 
  16         for i in range(55):
  17             self.SetRowSize(i, 20)
  18 
  19     def OnGridSelectCell(self, event):
  20         self.row, self.col = event.GetRow(), event.GetCol()
  21         control = self.GetParent().GetParent().position
  22         value =  self.GetColLabelValue(self.col) + self.GetRowLabelValue(self.row)
  23         control.SetValue(value)
  24         event.Skip()
  25 
  26 
  27 class Newt(wx.Frame):
  28     def __init__(self, parent, id, title):
  29         wx.Frame.__init__(self, parent, -1, title, size = ( 550, 500))
  30 
  31         fonts = ['Times New Roman', 'Times', 'Courier', 'Courier New', 'Helvetica', 'Sans', 'verdana', 'utkal', 'aakar', 'Arial']
  32         box = wx.BoxSizer(wx.VERTICAL)
  33         menuBar = wx.MenuBar()
  34 
  35         menu1 = wx.Menu()
  36         menuBar.Append(menu1, '&File')
  37         menu2 = wx.Menu()
  38         menuBar.Append(menu2, '&Edit')
  39         menu3 = wx.Menu()
  40         menuBar.Append(menu3, '&Edit')
  41         menu4 = wx.Menu()
  42         menuBar.Append(menu4, '&Insert')
  43         menu5 = wx.Menu()
  44         menuBar.Append(menu5, 'F&ormat')
  45         menu6 = wx.Menu()
  46         menuBar.Append(menu6, '&Tools')
  47         menu7 = wx.Menu()
  48         menuBar.Append(menu7, '&Data')
  49 
  50         menu7 = wx.Menu()
  51         menuBar.Append(menu7, '&Help')
  52 
  53 
  54         self.SetMenuBar(menuBar)
  55 
  56         toolbar1 = wx.ToolBar(self, -1, style= wx.TB_HORIZONTAL | wx.NO_BORDER | wx.TB_FLAT | wx.TB_TEXT)
  57         toolbar1.AddSimpleTool(-1, wx.Image('icons/stock_new.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'New', '')
  58         toolbar1.AddSimpleTool(-1, wx.Image('icons/stock_open.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'Open', '')
  59         toolbar1.AddSimpleTool(-1, wx.Image('icons/stock_save.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'Save', '')
  60         toolbar1.AddSeparator()
  61         toolbar1.AddSimpleTool(-1, wx.Image('icons/stock_cut.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'Cut', '')
  62         toolbar1.AddSimpleTool(-1, wx.Image('icons/stock_copy.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'Copy', '')
  63         toolbar1.AddSimpleTool(-1, wx.Image('icons/stock_paste.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'Paste', '')
  64         toolbar1.AddSimpleTool(-1, wx.Image('icons/stock_delete.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'Delete', '')
  65         toolbar1.AddSeparator()
  66         toolbar1.AddSimpleTool(-1, wx.Image('icons/stock_undo.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'Undo', '')
  67         toolbar1.AddSimpleTool(-1, wx.Image('icons/stock_redo.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'Redo', '')
  68         toolbar1.AddSeparator()
  69         toolbar1.AddSimpleTool(-1, wx.Image('icons/incr22.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'Sort Increasing', '')
  70         toolbar1.AddSimpleTool(-1, wx.Image('icons/decr22.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'Sort Decreasing', '')
  71         toolbar1.AddSeparator()
  72         toolbar1.AddSimpleTool(-1, wx.Image('icons/graph_guru_24.xpm', wx.BITMAP_TYPE_XPM).ConvertToBitmap(), 'Chart', '')
  73         toolbar1.AddSeparator()
  74         toolbar1.AddSimpleTool(-1, wx.Image('icons/stock_exit.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'Quit', '')
  75 
  76         toolbar1.Realize()
  77 
  78         toolbar2 = wx.ToolBar(self, wx.TB_HORIZONTAL | wx.TB_TEXT)
  79         self.position = wx.TextCtrl(toolbar2)
  80         font = wx.ComboBox(toolbar2, -1, value = 'Times', choices=fonts, size=(100, -1), style=wx.CB_DROPDOWN)
  81         font_height = wx.ComboBox(toolbar2, -1, value = '10',  choices=['10', '11', '12', '14', '16'], size=(50, -1), style=wx.CB_DROPDOWN)
  82         toolbar2.AddControl(self.position)
  83         toolbar2.AddControl(wx.StaticText(toolbar2, -1, '  '))
  84         toolbar2.AddControl(font)
  85         toolbar2.AddControl(wx.StaticText(toolbar2, -1, '  '))
  86         toolbar2.AddControl(font_height)
  87         toolbar2.AddSeparator()
  88         bold = wx.Image('icons/stock_text_bold.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap()
  89         toolbar2.AddCheckTool(-1, bold , shortHelp = 'Bold')
  90         italic = wx.Image('icons/stock_text_italic.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap()
  91         toolbar2.AddCheckTool(-1, italic,  shortHelp = 'Italic')
  92         under = wx.Image('icons/stock_text_underline.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap()
  93         toolbar2.AddCheckTool(-1, under, shortHelp = 'Underline')
  94         toolbar2.AddSeparator()
  95         toolbar2.AddSimpleTool(-1, wx.Image('icons/stock_text_align_left.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'Align Left', '')
  96         toolbar2.AddSimpleTool(-1, wx.Image('icons/stock_text_align_center.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'Center', '')
  97         toolbar2.AddSimpleTool(-1, wx.Image('icons/stock_text_align_right.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'Align Right', '')
  98 
  99         box.Add(toolbar1, border=5)
 100         box.Add((5,5) , 0)
 101         box.Add(toolbar2)
 102         box.Add((5,10) , 0)
 103 
 104         toolbar2.Realize()
 105         self.SetSizer(box)
 106         notebook = wx.Notebook(self, -1, style=wx.BOTTOM)
 107 
 108         sheet1 = MySheet(notebook)
 109         sheet2 = MySheet(notebook)
 110         sheet3 = MySheet(notebook)
 111         sheet1.SetFocus()
 112 
 113         notebook.AddPage(sheet1, 'Sheet1')
 114         notebook.AddPage(sheet2, 'Sheet2')
 115         notebook.AddPage(sheet3, 'Sheet3')
 116 
 117         box.Add(notebook, 1, wx.EXPAND)
 118 
 119         self.CreateStatusBar()
 120         self.Centre()
 121         self.Show(True)
 122 
 123 app = wx.App(0)
 124 newt = Newt(None, -1, 'SpreadSheet')
 125 app.MainLoop()

spreadsheet.png

Figure: spreadsheet.py

Tips And Tricks

In this section we will show some tips in wxPython.

PopupMenu

The following code was committed by Chris Barker on the wxPython-users mailing list. Popup menu is here implemented in a separate class. This way, you don't have to manually check, if the events were already bound.

Toggle line numbers
   1 #!/usr/bin/env python
   2 
   3 # popup.py
   4 
   5 import wx
   6 
   7 app = wx.PySimpleApp()
   8 
   9 class MyPopupMenu(wx.Menu):
  10     def __init__(self, WinName):
  11         wx.Menu.__init__(self)
  12 
  13         self.WinName = WinName
  14         item = wx.MenuItem(self, wx.NewId(), "Item One")
  15         self.AppendItem(item)
  16         self.Bind(wx.EVT_MENU, self.OnItem1, item)
  17         item = wx.MenuItem(self, wx.NewId(),"Item Two")
  18         self.AppendItem(item)
  19         self.Bind(wx.EVT_MENU, self.OnItem2, item)
  20         item = wx.MenuItem(self, wx.NewId(),"Item Three")
  21         self.AppendItem(item)
  22         self.Bind(wx.EVT_MENU, self.OnItem3, item)
  23 
  24     def OnItem1(self, event):
  25         print "Item One selected in the %s window"%self.WinName
  26 
  27     def OnItem2(self, event):
  28         print "Item Two selected in the %s window"%self.WinName
  29 
  30     def OnItem3(self, event):
  31         print "Item Three selected in the %s window"%self.WinName
  32 
  33 class MyWindow(wx.Window):
  34     def __init__(self, parent, color):
  35         wx.Window.__init__(self, parent, -1)
  36         self.color = color
  37         self.SetBackgroundColour(color)
  38         self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
  39 
  40     def OnRightDown(self,event):
  41         self.PopupMenu(MyPopupMenu(self.color), event.GetPosition())
  42 
  43 class MyFrame(wx.Frame):
  44     def __init__(self):
  45         wx.Frame.__init__(self,None, -1, "Test", size=(300, 200))
  46         sizer = wx.GridSizer(2,2,5,5)
  47         sizer.Add(MyWindow(self,"blue"),1,wx.GROW)
  48         sizer.Add(MyWindow(self,"yellow"),1,wx.GROW)
  49         sizer.Add(MyWindow(self,"red"),1,wx.GROW)
  50         sizer.Add(MyWindow(self,"green"),1,wx.GROW)
  51         self.SetSizer(sizer)
  52         self.Show()
  53 
  54 frame = MyFrame()
  55 app.SetTopWindow(frame)
  56 app.MainLoop()

The example is just a single frame. This frame is divided into four windows. If you right click on the frame, context menu pops up. Context menu consists of three commands. If you select any of them a message is sent to the console. It will say what item you selected plus the color of the window where you clicked with the mouse. This example shows the power of the object oriented programming. Imagine you would have to do it the other way, by calculating manually the position of the pointer!

Notice that the popup menu is implemented as a new class. This is a more elegant way of using popup menus as the following one, taken from the Demo application.

 def OnRightClick(self, event):
        # only do this part the first time so the events are only bound once
        if not hasattr(self, "popupID1"):
            self.popupID1 = wx.NewId()
            self.popupID2 = wx.NewId()
            self.Bind(wx.EVT_MENU, self.OnPopupOne, id=self.popupID1)
            self.Bind(wx.EVT_MENU, self.OnPopupTwo, id=self.popupID2)
        menu = wx.Menu()
        menu.Append(self.popupID1, "One")
        menu.Append(self.popupID2, "Two")
        self.PopupMenu(menu, event.GetPosition())
        menu.Destroy()
    def OnPopupOne(self, event):
        pass
    def OnPopupTwo(self, event):
        pass

There is one subtle thing in the code that needs some clarification. You only boud an event once. It resides in event table afterwards. If it is done in the constructor, everything is ok. But when you bound an event to a method in a method, you do it everytime when the method gets invoked. That's why we wrote a condition to ensure, we don't implement this overhead.

 if not hasattr(self, "popupID1"):
            self.popupID1 = wx.NewId()
            self.popupID2 = wx.NewId()
            self.Bind(wx.EVT_MENU, self.OnPopupOne, id=self.popupID1)
            self.Bind(wx.EVT_MENU, self.OnPopupTwo, id=self.popupID2)

The tiniest wxPython application

Feel free to contact me, if you can shorthen it. Even for one single character.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 import wx
   4 
   5 i = wx.App()
   6 
   7 wx.Frame(None).Show()
   8 
   9 i.MainLoop()

Interactive Button

This tip shows how to program an interactive Button. This button reacts to users actions. In our case, the button changes it's background colour. When you enter the area of the button widget with a mouse pointer,

EVT_ENTER_WINDOW event is generated. Simirarly, EVT_LEAVE_WINDOW event is generated, when you leave the area of the widget. So all you have to do is to bind those events to functions, that will change the colour/shape of the button widget appropriately.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # interactivebutton.py
   4 
   5 import wx
   6 
   7 from wxPython.lib.buttons import wxGenButton
   8 
   9 class MyPanel(wx.Panel):
  10     def __init__(self, parent, ID):
  11         wx.Panel.__init__(self, parent, ID, wx.DefaultPosition)
  12 
  13         self.btn = wxGenButton(self, -1, "button", pos = wx.Point(125,100), size=(-1, -1))
  14         self.btn.SetBezelWidth(1)
  15         self.btn.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterButton)
  16         self.btn.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveButton)
  17 
  18     def OnEnterButton(self, event):
  19         self.btn.SetBackgroundColour(wx.Color(128, 128,128))
  20         self.btn.Refresh()
  21 
  22     def OnLeaveButton(self, event):
  23         self.btn.SetBackgroundColour(wx.Color(212, 208,200))
  24         self.btn.Refresh()
  25 
  26 class MyApp(wx.App):
  27     def OnInit(self):
  28         frame = wx.Frame(None, -1, "interactivebutton.py", wx.DefaultPosition, wx.Size(350,300))
  29         mypanel = MyPanel(frame, -1)
  30         frame.Centre()
  31         frame.Show(True)
  32         self.SetTopWindow(frame)
  33         return True
  34 
  35 app = MyApp(0)
  36 app.MainLoop()

I have usedwx.GenButton instead of basic wx.Button. wx.GenButton enables to change border settigs, which I find attractive. But wx.Button would work as well.

Error handling without dialogs

When an error occurs in an application, an error dialog usually appears. This might get annoying. I have noticed a better solution in SAP system. When a user enters an invalid command, statusbar turs red and an error message is displayed on stausbar. The red colour catches the eye and the user can easily read the error message. The following code mimics this situation.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # Isabelle
   4 
   5 import wx
   6 
   7 ID_TIMER = 1
   8 ID_EXIT  = 2
   9 ID_ABOUT = 3
  10 ID_BUTTON = 4
  11 
  12 class Isabelle(wx.Frame):
  13     def __init__(self, parent, id, title):
  14         wx.Frame.__init__(self, parent, id, title)
  15 
  16         self.timer = wx.Timer(self, ID_TIMER)
  17         self.blick = 0
  18 
  19         file = wx.Menu()
  20         file.Append(ID_EXIT, '&Quit\tCtrl+Q', 'Quit Isabelle')
  21 
  22         help = wx.Menu()
  23         help.Append(ID_ABOUT, '&About', 'O Programe')
  24 
  25 
  26         menubar = wx.MenuBar()
  27         menubar.Append(file, '&File')
  28         menubar.Append(help, '&Help')
  29         self.SetMenuBar(menubar)
  30 
  31         toolbar = wx.ToolBar(self, -1)
  32         self.tc = wx.TextCtrl(toolbar, -1, size=(100, -1))
  33         btn = wx.Button(toolbar, ID_BUTTON, 'Ok', size=(40, 28))
  34 
  35         toolbar.AddControl(self.tc)
  36         toolbar.AddSeparator()
  37         toolbar.AddControl(btn)
  38         toolbar.Realize()
  39         self.SetToolBar(toolbar)
  40 
  41         self.Bind(wx.EVT_BUTTON, self.OnLaunchCommandOk, id=ID_BUTTON)
  42         self.Bind(wx.EVT_MENU, self.OnAbout, id=ID_ABOUT)
  43         self.Bind(wx.EVT_MENU, self.OnExit, id=ID_EXIT)
  44         self.Bind(wx.EVT_TIMER, self.OnTimer, id=ID_TIMER)
  45 
  46         self.panel = wx.Panel(self, -1, (0, 0), (500 , 300))
  47         self.panel.SetBackgroundColour('GRAY')
  48         self.sizer=wx.BoxSizer(wx.VERTICAL)
  49         self.sizer.Add(self.panel, 1, wx.EXPAND)
  50         self.SetSizer(self.sizer)
  51         self.statusbar = self.CreateStatusBar()
  52         self.statusbar.SetStatusText('Welcome to Isabelle')
  53         self.Centre()
  54 
  55     def OnExit(self, event):
  56         dlg = wx.MessageDialog(self, 'Are you sure to quit Isabelle?', 'Please Confirm', wx.YES_NO |
  57                 wx.NO_DEFAULT | wx.ICON_QUESTION)
  58         if dlg.ShowModal() == wx.ID_YES:
  59             self.Close(True)
  60 
  61 
  62     def OnAbout(self, event):
  63         dlg = wx.MessageDialog(self, 'Isabelle\t\n' '2004\t', 'About',
  64                  wx.OK | wx.ICON_INFORMATION)
  65         dlg.ShowModal()
  66         dlg.Destroy()
  67 
  68 
  69     def OnLaunchCommandOk(self, event):
  70         input = self.tc.GetValue()
  71         if input == '/bye':
  72             self.OnExit(self)
  73         elif input == '/about':
  74             self.OnAbout(self)
  75         elif input == '/bell':
  76             wx.Bell()
  77         else:
  78             self.statusbar.SetBackgroundColour('RED')
  79             self.statusbar.SetStatusText('Unknown Command')
  80             self.statusbar.Refresh()
  81             self.timer.Start(50)
  82 
  83         self.tc.Clear()
  84 
  85     def OnTimer(self, event):
  86         self.blick += 1
  87         if self.blick == 25:
  88             self.statusbar.SetBackgroundColour('#E0E2EB')
  89             self.statusbar.Refresh()
  90             self.timer.Stop()
  91             self.blick = 0
  92 
  93 app = wx.App()
  94 Isabelle(None, -1, 'Isabelle')
  95 app.MainLoop()

There is awx.TextCtrl on the Statusbar. There you enter your commands. We have defined three commands. /bye, /about and /beep. If you mistype any of them, Statusbar turns red and displays an error. This is done with the wx.Timer class. Firstly, you need to create a wx.Timer object.

self.timer = wx.Timer(self, 1)

Then you bind this newly created object to a specific method -- in our caseOnTimer.

wx.EVT_TIMER(self,  1, self.OnTimer)

When the user enters an invalid command, the timer object is started with the following code.

self.timer.Start(10)

Every 10 millisecondsOnTimer method is called. If variable self.blick equals 25, we stop the timer with

self.timer.Stop()

isabelle.png

Figure: isabelle.py

UndoRedoFramework

Many applications have the ability to undo and redo the user's actions. The following example shows how it can be accomplished in wxPython.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # newt.py
   4 
   5 from wxPython.lib.sheet import *
   6 from wx.lib.plot import *
   7 import wx
   8 
   9 stockUndo = []
  10 stockRedo = []
  11 
  12 class UndoText:
  13     def __init__(self, sheet, text1, text2, row, column):
  14         self.RedoText =  text2
  15         self.row = row
  16         self.col = column
  17         self.UndoText = text1
  18         self.sheet = sheet
  19 
  20     def undo(self):
  21         self.RedoText = self.sheet.GetCellValue(self.row, self.col)
  22         if self.UndoText ==  None:
  23             self.sheetSetCellValue('')
  24         else: self.sheet.SetCellValue(self.row, self.col, self.UndoText)
  25 
  26     def redo(self):
  27         if self.RedoText == None:
  28             self.sheet.SetCellValue('')
  29         else: self.sheet.SetCellValue(self.row, self.col, self.RedoText)
  30 
  31 class UndoColSize:
  32     def __init__(self, sheet, position, size):
  33         self.sheet = sheet
  34         self.pos = position
  35         self.RedoSize = size
  36         self.UndoSize = 80
  37 
  38     def undo(self):
  39         self.RedoSize = self.sheet.GetColSize(self.pos)
  40         self.sheet.SetColSize(self.pos, self.UndoSize)
  41         self.sheet.ForceRefresh()
  42 
  43     def redo(self):
  44         self.UndoSize = 80
  45         self.sheet.SetColSize(self.pos, self.RedoSize)
  46         self.sheet.ForceRefresh()
  47 
  48 class UndoRowSize:
  49     def __init__(self, sheet, position, size):
  50         self.sheet = sheet
  51         self.pos = position
  52         self.RedoSize = size
  53         self.UndoSize = 20
  54 
  55     def undo(self):
  56         self.RedoSize = self.sheet.GetRowSize(self.pos)
  57         self.sheet.SetRowSize(self.pos, self.UndoSize)
  58         self.sheet.ForceRefresh()
  59 
  60     def redo(self):
  61         self.UndoSize = 20
  62         self.sheet.SetRowSize(self.pos, self.RedoSize)
  63         self.sheet.ForceRefresh()
  64 
  65 class MySheet(CSheet):
  66     instance = 0
  67     def __init__(self, parent):
  68         CSheet.__init__(self, parent)
  69         self.SetLabelBackgroundColour('#DBD4D4')
  70         self.SetRowLabelAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE)
  71         self.text = ''
  72 
  73     def OnCellChange(self, event):
  74         toolbar = self.GetParent().toolbar1
  75         if not toolbar.GetToolEnabled(808):
  76                 toolbar.EnableTool(808, True)
  77         r = event.GetRow()
  78         c = event.GetCol()
  79         text = self.GetCellValue(r, c)
  80         # self.text - text before change
  81         # text - text after change
  82         undo = UndoText(self, self.text, text, r, c)
  83         stockUndo.append(undo)
  84 
  85         if stockRedo:
  86             # this might be surprising, but it is a standard behaviour
  87             # in all spreadsheets
  88             del stockRedo[:]
  89             toolbar.EnableTool(809, False)
  90 
  91     def OnColSize(self, event):
  92         toolbar = self.GetParent().toolbar1
  93 
  94         if not toolbar.GetToolEnabled(808):
  95                 toolbar.EnableTool(808, True)
  96 
  97         pos =  event.GetRowOrCol()
  98         size = self.GetColSize(pos)
  99         undo = UndoColSize(self, pos, size)
 100         stockUndo.append(undo)
 101 
 102         if stockRedo:
 103             del stockRedo[:]
 104             toolbar.EnableTool(809, False)
 105 
 106     def OnRowSize(self, event):
 107         toolbar = self.GetParent().toolbar1
 108         if not toolbar.GetToolEnabled(808):
 109                 toolbar.EnableTool(808, True)
 110 
 111         pos =  event.GetRowOrCol()
 112         size = self.GetRowSize(pos)
 113         undo = UndoRowSize(self, pos, size)
 114 
 115         stockUndo.append(undo)
 116         if stockRedo:
 117             del stockRedo[:]
 118             toolbar.EnableTool(809, False)
 119 
 120 class Newt(wx.Frame):
 121     def __init__(self,parent,id,title):
 122         wx.Frame.__init__(self,parent,-4, title, size = ( 550, 500),
 123                          style=wx.DEFAULT_FRAME_STYLE|wx.NO_FULL_REPAINT_ON_RESIZE)
 124 
 125         box = wx.BoxSizer(wx.VERTICAL)
 126         menuBar = wx.MenuBar()
 127         menu1 = wx.Menu()
 128         quit = wx.MenuItem(menu1, 105, "&Quit\tCtrl+Q", "Quits Newt")
 129         quit.SetBitmap(wx.Image('stock_exit-16.png',
 130                                wx.BITMAP_TYPE_PNG).ConvertToBitmap())
 131         menu1.AppendItem(quit)
 132         menuBar.Append(menu1, "&File")
 133         self.Bind(wx.EVT_MENU, self.OnQuitNewt, id=105)
 134         self.SetMenuBar(menuBar)
 135         # Setting up Toolbar
 136         self.toolbar1 = wx.ToolBar(self, id=-1, style=wx.TB_HORIZONTAL | wx.NO_BORDER |
 137                                         wx.TB_FLAT | wx.TB_TEXT)
 138         self.toolbar1.AddSimpleTool(808,
 139               wx.Image('stock_undo.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap(),
 140               'Undo', '')
 141         self.toolbar1.AddSimpleTool(809,
 142               wx.Image('stock_redo.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap(),
 143               'Redo', '')
 144         self.toolbar1.EnableTool(808, False)
 145         self.toolbar1.EnableTool(809, False)
 146         self.toolbar1.AddSeparator()
 147         self.toolbar1.AddSimpleTool(813,
 148               wx.Image('stock_exit.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap(),
 149               'Quit', '')
 150         self.toolbar1.Realize()
 151         self.toolbar1.Bind(wx.EVT_TOOL, self.OnUndo, id=808)
 152         self.toolbar1.Bind(wx.EVT_TOOL, self.OnRedo, id=809)
 153         self.toolbar1.Bind(wx.EVT_TOOL, self.OnQuitNewt, id=813)
 154         box.Add(self.toolbar1, border=5)
 155         box.Add((5,10),0)
 156         self.SetSizer(box)
 157         self.sheet1 = MySheet(self)
 158         self.sheet1.SetNumberRows(55)
 159         self.sheet1.SetNumberCols(25)
 160         for i in range(self.sheet1.GetNumberRows()):
 161             self.sheet1.SetRowSize(i, 20)
 162         self.sheet1.SetFocus()
 163         box.Add(self.sheet1, 1, wx.EXPAND)
 164         self.CreateStatusBar()
 165         self.Centre()
 166         self.Show(True)
 167 
 168     def OnUndo(self, event):
 169         if len(stockUndo) == 0:
 170             return
 171 
 172         a = stockUndo.pop()
 173         if len(stockUndo) == 0:
 174             self.toolbar1.EnableTool(808, False)
 175 
 176         a.undo()
 177         stockRedo.append(a)
 178         self.toolbar1.EnableTool(809, True)
 179 
 180     def OnRedo(self, event):
 181         if len(stockRedo) == 0:
 182             return
 183 
 184         a = stockRedo.pop()
 185         if len(stockRedo) == 0:
 186             self.toolbar1.EnableTool(809, False)
 187 
 188         a.redo()
 189         stockUndo.append(a)
 190         self.toolbar1.EnableTool(808, True)
 191 
 192     def OnQuitNewt(self, event):
 193         self.Close(True)
 194 
 195 app = wx.PySimpleApp()
 196 newt = Newt(None, -1, "Newt")
 197 app.MainLoop()

In our example, we want to undo and redo cell text changes and column and row size changes. So we must bind relevant events to our methods. These bindings are not visible in our sample code. You can find them in sheet.py file, in CSheet class:

self.Bind(wx.grid.EVT_GRID_ROW_SIZE, self.OnRowSize)
self.Bind(wx.grid.EVT_GRID_COL_SIZE, self.OnColSize)
self.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnCellChange)

In these three methods we create Undo objects. These objects areUndoText, UndoColSize and UndoRowSize. Each object has two methods. undo() and redo(). They are responsible for bringing to the state of the application before the change was done and vice versa. The objects are then appended to stockUndo list. This way we ensure, that all necessary changes are stored. Finally, when we press undo, redo buttons, we call OnUndo() and OnRedo() methods. The following method calls actually do the job:

a.undo()
a.redo()

The objects move between stockUndo and stockRedo lists accordingly. Also when there are no objects left, we disable a button with theEnableTool() method.

newt.png

Figure: newt.py

Gripts

In this section we will show some small, complete scripts. These graphical scripts or "gripts" will demonstrate various areas in programming. Programming in Python, wxPython is easier than in most other toolkits. But it is still a laborious task. There is a long, long way from easy scripts to professional applications.

Tom

Each application should have a good name. Short and easily remembered. So, we have Tom. A simple gript that sends an email.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # Tom
   4 
   5 import wx
   6 import smtplib
   7 
   8 class Tom(wx.Dialog):
   9     def __init__(self, parent, id, title):
  10         wx.Dialog.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(400, 420))
  11 
  12         panel = wx.Panel(self, -1)
  13         vbox = wx.BoxSizer(wx.VERTICAL)
  14         hbox1 = wx.BoxSizer(wx.HORIZONTAL)
  15         hbox2 = wx.BoxSizer(wx.HORIZONTAL)
  16         hbox3 = wx.BoxSizer(wx.HORIZONTAL)
  17         st1 = wx.StaticText(panel, -1, 'From: ')
  18         st2 = wx.StaticText(panel, -1, 'To: ')
  19         st3 = wx.StaticText(panel, -1, 'Subject: ')
  20         self.tc1 = wx.TextCtrl(panel, -1, size=(180, -1))
  21         self.tc2 = wx.TextCtrl(panel, -1, size=(180, -1))
  22         self.tc3 = wx.TextCtrl(panel, -1, size=(180, -1))
  23         self.write = wx.TextCtrl(panel, -1, style=wx.TE_MULTILINE)
  24         button_send = wx.Button(panel, 1, 'Send')
  25         hbox1.Add(st1, 0, wx.LEFT, 10)
  26         hbox1.Add(self.tc1, 0, wx.LEFT, 20)
  27         hbox2.Add(st2, 0, wx.LEFT, 10)
  28         hbox2.Add(self.tc2, 0, wx.LEFT, 35)
  29         hbox3.Add(st3, 0, wx.LEFT, 10)
  30         hbox3.Add(self.tc3, 0)
  31         vbox.Add(hbox1, 0, wx.TOP, 10)
  32         vbox.Add(hbox2, 0, wx.TOP, 10)
  33         vbox.Add(hbox3, 0, wx.TOP, 10)
  34         vbox.Add(self.write, 1, wx.EXPAND | wx.TOP | wx.RIGHT | wx.LEFT, 15)
  35         vbox.Add(button_send, 0, wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, 20)
  36         self.Bind(wx.EVT_BUTTON, self.OnSend, id=1)
  37         panel.SetSizer(vbox)
  38         self.Centre()
  39 
  40     def OnSend(self, event):
  41         sender = self.tc1.GetValue()
  42         recipient = self.tc2.GetValue()
  43         subject = self.tc3.GetValue()
  44         text = self.write.GetValue()
  45         header = 'From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n' % (sender, recipient, subject)
  46         message = header + text
  47         try:
  48             server = smtplib.SMTP('mail.chello.sk')
  49             server.sendmail(sender, recipient, message)
  50             server.quit()
  51             dlg = wx.MessageDialog(self, 'Email was successfully sent', 'Success', wx.OK | wx.ICON_INFORMATION)
  52             dlg.ShowModal()
  53             dlg.Destroy()
  54         except smtplib.SMTPException, error:
  55             dlg = wx.MessageDialog(self, 'Failed to send email', 'Error', wx.OK | wx.ICON_ERROR)
  56             dlg.ShowModal()
  57             dlg.Destroy()
  58 
  59 class MyApp(wx.App):
  60     def OnInit(self):
  61         frame = Tom(None, -1, 'Tom')
  62         frame.ShowModal()
  63         frame.Destroy()
  64         return True
  65 
  66 app = MyApp(0)
  67 app.MainLoop()

For working with emails we need to import smtp module.

import smtplib

From, To and Subject options must be separated by carriedge return and newline as shown here. This weird thing is requested by RFC 821 norm. So we must follow it.

header = 'From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n' % (sender, recipient, subject)

Next we create an SMTP connection. Here you specify your settings. Each ISP gives you the name of the pop and smtp servers. In my case, 'mail.chello.sk' is a name for both. A mail is sent by calling the sendmail() method. Finally, we quit the connection with the quit() method.

server = smtplib.SMTP('mail.chello.sk')
server.sendmail(sender, recipient, message)
server.quit()

tom.png

Figure: Tom

Editor

Here we have a simple text editor. Notice the use of exceptions. It is a programmer's task to find and handle bugs. This includes doing such nasty things like opening pictures in an editor, simulating all possible situations. If a script raises an unhandled exception, we simply write a code that handles this.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # Editor
   4 
   5 import wx
   6 import os
   7 
   8 class Editor(wx.Frame):
   9     def __init__(self, parent, id, title):
  10         wx.Frame.__init__(self, parent, id, title, size=(600, 500))
  11 
  12         # variables
  13         self.modify = False
  14         self.last_name_saved = ''
  15         self.replace = False
  16 
  17         # setting up menubar
  18         menubar = wx.MenuBar()
  19 
  20         file = wx.Menu()
  21         new = wx.MenuItem(file, 101, '&New\tCtrl+N', 'Creates a new document')
  22         new.SetBitmap(wx.Bitmap('icons/stock_new-16.png'))
  23         file.AppendItem(new)
  24 
  25         open = wx.MenuItem(file, 102, '&Open\tCtrl+O', 'Open an existing file')
  26         open.SetBitmap(wx.Bitmap('icons/stock_open-16.png'))
  27         file.AppendItem(open)
  28         file.AppendSeparator()
  29 
  30         save = wx.MenuItem(file, 103, '&Save\tCtrl+S', 'Save the file')
  31         save.SetBitmap(wx.Bitmap('icons/stock_save-16.png'))
  32         file.AppendItem(save)
  33 
  34         saveas = wx.MenuItem(file, 104, 'Save &As...\tShift+Ctrl+S', 'Save the file with a different name')
  35         saveas.SetBitmap(wx.Bitmap('icons/stock_save_as-16.png'))
  36         file.AppendItem(saveas)
  37         file.AppendSeparator()
  38 
  39         quit = wx.MenuItem(file, 105, '&Quit\tCtrl+Q', 'Quit the Application')
  40         quit.SetBitmap(wx.Bitmap('icons/stock_exit-16.png'))
  41         file.AppendItem(quit)
  42 
  43         edit = wx.Menu()
  44         cut = wx.MenuItem(edit, 106, '&Cut\tCtrl+X', 'Cut the Selection')
  45         cut.SetBitmap(wx.Bitmap('icons/stock_cut-16.png'))
  46         edit.AppendItem(cut)
  47 
  48         copy = wx.MenuItem(edit, 107, '&Copy\tCtrl+C', 'Copy the Selection')
  49         copy.SetBitmap(wx.Bitmap('icons/stock_copy-16.png'))
  50         edit.AppendItem(copy)
  51 
  52         paste = wx.MenuItem(edit, 108, '&Paste\tCtrl+V', 'Paste text from clipboard')
  53         paste.SetBitmap(wx.Bitmap('icons/stock_paste-16.png'))
  54         edit.AppendItem(paste)
  55 
  56         delete = wx.MenuItem(edit, 109, '&Delete', 'Delete the selected text')
  57         delete.SetBitmap(wx.Bitmap('icons/stock_delete-16.png',))
  58 
  59         edit.AppendItem(delete)
  60         edit.AppendSeparator()
  61         edit.Append(110, 'Select &All\tCtrl+A', 'Select the entire text')
  62 
  63         view = wx.Menu()
  64         view.Append(111, '&Statusbar', 'Show StatusBar')
  65 
  66         help = wx.Menu()
  67         about = wx.MenuItem(help, 112, '&About\tF1', 'About Editor')
  68         about.SetBitmap(wx.Bitmap('icons/stock_about-16.png'))
  69         help.AppendItem(about)
  70 
  71         menubar.Append(file, '&File')
  72         menubar.Append(edit, '&Edit')
  73         menubar.Append(view, '&View')
  74         menubar.Append(help, '&Help')
  75         self.SetMenuBar(menubar)
  76 
  77         self.Bind(wx.EVT_MENU, self.NewApplication, id=101)
  78         self.Bind(wx.EVT_MENU, self.OnOpenFile, id=102)
  79         self.Bind(wx.EVT_MENU, self.OnSaveFile, id=103)
  80         self.Bind(wx.EVT_MENU, self.OnSaveAsFile, id=104)
  81         self.Bind(wx.EVT_MENU, self.QuitApplication, id=105)
  82         self.Bind(wx.EVT_MENU, self.OnCut, id=106)
  83         self.Bind(wx.EVT_MENU, self.OnCopy, id=107)
  84         self.Bind(wx.EVT_MENU, self.OnPaste, id=108)
  85         self.Bind(wx.EVT_MENU, self.OnDelete, id=109)
  86         self.Bind(wx.EVT_MENU, self.OnSelectAll, id=110)
  87         self.Bind(wx.EVT_MENU, self.ToggleStatusBar, id=111)
  88         self.Bind(wx.EVT_MENU, self.OnAbout, id=112)
  89 
  90         # setting up toolbar
  91         self.toolbar = self.CreateToolBar( wx.TB_HORIZONTAL | wx.NO_BORDER | wx.TB_FLAT | wx.TB_TEXT )
  92         self.toolbar.AddSimpleTool(801, wx.Bitmap('icons/stock_new.png'), 'New', '')
  93         self.toolbar.AddSimpleTool(802, wx.Bitmap('icons/stock_open.png'), 'Open', '')
  94         self.toolbar.AddSimpleTool(803, wx.Bitmap('icons/stock_save.png'), 'Save', '')
  95         self.toolbar.AddSeparator()
  96 
  97         self.toolbar.AddSimpleTool(804, wx.Bitmap('icons/stock_cut.png'), 'Cut', '')
  98         self.toolbar.AddSimpleTool(805, wx.Bitmap('icons/stock_copy.png'), 'Copy', '')
  99         self.toolbar.AddSimpleTool(806, wx.Bitmap('icons/stock_paste.png'), 'Paste', '')
 100         self.toolbar.AddSeparator()
 101 
 102         self.toolbar.AddSimpleTool(807, wx.Bitmap('icons/stock_exit.png'), 'Exit', '')
 103         self.toolbar.Realize()
 104 
 105         self.Bind(wx.EVT_TOOL, self.NewApplication, id=801)
 106         self.Bind(wx.EVT_TOOL, self.OnOpenFile, id=802)
 107         self.Bind(wx.EVT_TOOL, self.OnSaveFile, id=803)
 108         self.Bind(wx.EVT_TOOL, self.OnCut, id=804)
 109         self.Bind(wx.EVT_TOOL, self.OnCopy, id=805)
 110         self.Bind(wx.EVT_TOOL, self.OnPaste, id=806)
 111         self.Bind(wx.EVT_TOOL, self.QuitApplication, id=807)
 112 
 113         self.text = wx.TextCtrl(self, 1000, '', size=(-1, -1), style=wx.TE_MULTILINE | wx.TE_PROCESS_ENTER)
 114         self.text.SetFocus()
 115         self.text.Bind(wx.EVT_TEXT, self.OnTextChanged, id=1000)
 116         self.text.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
 117 
 118         self.Bind(wx.EVT_CLOSE, self.QuitApplication)
 119 
 120         self.StatusBar()
 121 
 122         self.Centre()
 123         self.Show(True)
 124 
 125     def NewApplication(self, event):
 126         editor = Editor(None, -1, 'Editor')
 127         editor.Centre()
 128         editor.Show()
 129 
 130     def OnOpenFile(self, event):
 131         file_name = os.path.basename(self.last_name_saved)
 132         if self.modify:
 133             dlg = wx.MessageDialog(self, 'Save changes?', '', wx.YES_NO | wx.YES_DEFAULT | wx.CANCEL |
 134                         wx.ICON_QUESTION)
 135             val = dlg.ShowModal()
 136             if val == wx.ID_YES:
 137                 self.OnSaveFile(event)
 138                 self.DoOpenFile()
 139             elif val == wx.ID_CANCEL:
 140                 dlg.Destroy()
 141             else:
 142                 self.DoOpenFile()
 143         else:
 144             self.DoOpenFile()
 145 
 146     def DoOpenFile(self):
 147         wcd = 'All files (*)|*|Editor files (*.ef)|*.ef|'
 148         dir = os.getcwd()
 149         open_dlg = wx.FileDialog(self, message='Choose a file', defaultDir=dir, defaultFile='',
 150                         wildcard=wcd, style=wx.OPEN|wx.CHANGE_DIR)
 151         if open_dlg.ShowModal() == wx.ID_OK:
 152             path = open_dlg.GetPath()
 153 
 154             try:
 155                 file = open(path, 'r')
 156                 text = file.read()
 157                 file.close()
 158                 if self.text.GetLastPosition():
 159                     self.text.Clear()
 160                 self.text.WriteText(text)
 161                 self.last_name_saved = path
 162                 self.statusbar.SetStatusText('', 1)
 163                 self.modify = False
 164 
 165             except IOError, error:
 166                 dlg = wx.MessageDialog(self, 'Error opening file\n' + str(error))
 167                 dlg.ShowModal()
 168 
 169             except UnicodeDecodeError, error:
 170                 dlg = wx.MessageDialog(self, 'Error opening file\n' + str(error))
 171                 dlg.ShowModal()
 172 
 173         open_dlg.Destroy()
 174 
 175     def OnSaveFile(self, event):
 176         if self.last_name_saved:
 177 
 178             try:
 179                 file = open(self.last_name_saved, 'w')
 180                 text = self.text.GetValue()
 181                 file.write(text)
 182                 file.close()
 183                 self.statusbar.SetStatusText(os.path.basename(self.last_name_saved) + ' saved', 0)
 184                 self.modify = False
 185                 self.statusbar.SetStatusText('', 1)
 186 
 187             except IOError, error:
 188                 dlg = wx.MessageDialog(self, 'Error saving file\n' + str(error))
 189                 dlg.ShowModal()
 190         else:
 191             self.OnSaveAsFile(event)
 192 
 193     def OnSaveAsFile(self, event):
 194         wcd='All files(*)|*|Editor files (*.ef)|*.ef|'
 195         dir = os.getcwd()
 196         save_dlg = wx.FileDialog(self, message='Save file as...', defaultDir=dir, defaultFile='',
 197                         wildcard=wcd, style=wx.SAVE | wx.OVERWRITE_PROMPT)
 198         if save_dlg.ShowModal() == wx.ID_OK:
 199             path = save_dlg.GetPath()
 200 
 201             try:
 202                 file = open(path, 'w')
 203                 text = self.text.GetValue()
 204                 file.write(text)
 205                 file.close()
 206                 self.last_name_saved = os.path.basename(path)
 207                 self.statusbar.SetStatusText(self.last_name_saved + ' saved', 0)
 208                 self.modify = False
 209                 self.statusbar.SetStatusText('', 1)
 210 
 211             except IOError, error:
 212                 dlg = wx.MessageDialog(self, 'Error saving file\n' + str(error))
 213                 dlg.ShowModal()
 214         save_dlg.Destroy()
 215 
 216     def OnCut(self, event):
 217         self.text.Cut()
 218 
 219     def OnCopy(self, event):
 220         self.text.Copy()
 221 
 222     def OnPaste(self, event):
 223         self.text.Paste()
 224 
 225     def QuitApplication(self, event):
 226         if self.modify:
 227             dlg = wx.MessageDialog(self, 'Save before Exit?', '', wx.YES_NO | wx.YES_DEFAULT |
 228                         wx.CANCEL | wx.ICON_QUESTION)
 229             val = dlg.ShowModal()
 230             if val == wx.ID_YES:
 231                 self.OnSaveFile(event)
 232                 if not self.modify:
 233                     wx.Exit()
 234             elif val == wx.ID_CANCEL:
 235                 dlg.Destroy()
 236             else:
 237                 self.Destroy()
 238         else:
 239             self.Destroy()
 240 
 241     def OnDelete(self, event):
 242         frm, to = self.text.GetSelection()
 243         self.text.Remove(frm, to)
 244 
 245     def OnSelectAll(self, event):
 246         self.text.SelectAll()
 247 
 248     def OnTextChanged(self, event):
 249         self.modify = True
 250         self.statusbar.SetStatusText(' modified', 1)
 251         event.Skip()
 252 
 253     def OnKeyDown(self, event):
 254         keycode = event.GetKeyCode()
 255         if keycode == wx.WXK_INSERT:
 256             if not self.replace:
 257                 self.statusbar.SetStatusText('INS', 2)
 258                 self.replace = True
 259             else:
 260                 self.statusbar.SetStatusText('', 2)
 261                 self.replace = False
 262         event.Skip()
 263 
 264     def ToggleStatusBar(self, event):
 265         if self.statusbar.IsShown():
 266             self.statusbar.Hide()
 267         else:
 268             self.statusbar.Show()
 269 
 270     def StatusBar(self):
 271         self.statusbar = self.CreateStatusBar()
 272         self.statusbar.SetFieldsCount(3)
 273         self.statusbar.SetStatusWidths([-5, -2, -1])
 274 
 275     def OnAbout(self, event):
 276         dlg = wx.MessageDialog(self, '\tEditor\t\n Another Tutorial\njan bodnar 2005-2006',
 277                                 'About Editor', wx.OK | wx.ICON_INFORMATION)
 278         dlg.ShowModal()
 279         dlg.Destroy()
 280 
 281 app = wx.App()
 282 Editor(None, -1, 'Editor')
 283 app.MainLoop()

editor.png

Figure: Editor

Kika

Kika is a gript that connects to an ftp site. If a login is successfull, Kika shows a connected icon on the statusbar. Otherwise, a disconnected icon is displayed. We use an ftplib module from the python standard library. If you do not have an ftp account, you can try to login to some anonymous ftp sites.

Toggle line numbers
   1 #!/usr/bin/python
   2 
   3 # kika.py
   4 
   5 from ftplib import FTP, all_errors
   6 import wx
   7 
   8 class MyStatusBar(wx.StatusBar):
   9     def __init__(self, parent):
  10         wx.StatusBar.__init__(self, parent)
  11 
  12         self.SetFieldsCount(2)
  13         self.SetStatusText('Welcome to Kika', 0)
  14         self.SetStatusWidths([-5, -2])
  15         self.icon = wx.StaticBitmap(self, -1, wx.Bitmap('icons/disconnected.png'))
  16         self.Bind(wx.EVT_SIZE, self.OnSize)
  17         self.PlaceIcon()
  18 
  19     def PlaceIcon(self):
  20         rect = self.GetFieldRect(1)
  21         self.icon.SetPosition((rect.x+3, rect.y+3))
  22 
  23     def OnSize(self, event):
  24         self.PlaceIcon()
  25 
  26 
  27 class MyFrame(wx.Frame):
  28     def __init__(self, parent, id, title):
  29         wx.Frame.__init__(self, parent, id, title, size=(250, 270))
  30 
  31         wx.StaticText(self, -1, 'Ftp site', (10, 20))
  32         wx.StaticText(self, -1, 'Login', (10, 60))
  33         wx.StaticText(self, -1, 'Password', (10, 100))
  34 
  35         self.ftpsite = wx.TextCtrl(self, -1, '',  (110, 15), (120, -1))
  36         self.login = wx.TextCtrl(self, -1, '',  (110, 55), (120, -1))
  37         self.password = wx.TextCtrl(self, -1, '',  (110, 95), (120, -1), style=wx.TE_PASSWORD)
  38 
  39         self.ftp = None
  40 
  41         con = wx.Button(self, 1, 'Connect', (10, 160))
  42         discon = wx.Button(self, 2, 'DisConnect', (120, 160))
  43 
  44         self.Bind(wx.EVT_BUTTON, self.OnConnect, id=1)
  45         self.Bind(wx.EVT_BUTTON, self.OnDisConnect, id=2)
  46 
  47         self.statusbar = MyStatusBar(self)
  48         self.SetStatusBar(self.statusbar)
  49         self.Centre()
  50 
  51     def OnConnect(self, event):
  52         if not self.ftp:
  53             ftpsite = self.ftpsite.GetValue()
  54             login = self.login.GetValue()
  55             password = self.password.GetValue()
  56 
  57             try:
  58                 self.ftp = FTP(ftpsite)
  59                 var = self.ftp.login(login, password)
  60                 self.statusbar.SetStatusText('User connected')
  61                 self.statusbar.icon.SetBitmap(wx.Bitmap('icons/connected.png'))
  62 
  63             except AttributeError:
  64                 self.statusbar.SetForegroundColour(wx.RED)
  65                 self.statusbar.SetStatusText('Incorrect params')
  66                 self.ftp = None
  67 
  68             except all_errors, err:
  69                 self.statusbar.SetStatusText(str(err))
  70                 self.ftp = None
  71 
  72     def OnDisConnect(self, event):
  73         if self.ftp:
  74             self.ftp.quit()
  75             self.ftp = None
  76             self.statusbar.SetStatusText('User disconnected')
  77             self.statusbar.icon.SetBitmap(wx.Bitmap('icons/disconnected.png'))
  78 
  79 class MyApp(wx.App):
  80     def OnInit(self):
  81         frame = MyFrame(None, -1, 'Kika')
  82         frame.Show(True)
  83         return True
  84 
  85 app = MyApp(0)
  86 app.MainLoop()

Notice that each time the window is resized, we must position our icon to a new place.

def PlaceIcon(self):
    rect = self.GetFieldRect(1)
    self.icon.SetPosition((rect.x+3, rect.y+3))

kika.png

Figure: Kika

Appendix

Cursor IDs

wx.CURSOR_ARROW

wx.CURSOR_RIGHT_ARROW

wx.CURSOR_BLANK

wx.CURSOR_BULLSEYE

wx.CURSOR_CHAR

wx.CURSOR_CROSS

wx.CURSOR_HAND

wx.CURSOR_IBEAM

wx.CURSOR_LEFT_BUTTON

wx.CURSOR_MAGNIFIER

wx.CURSOR_MIDDLE_BUTTON

wx.CURSOR_NO_ENTRY

wx.CURSOR_PAINT_BRUSH

wx.CURSOR_PENCIL

wx.CURSOR_POINT_LEFT

wx.CURSOR_POINT_RIGHT

wx.CURSOR_QUESTION_ARROW

wx.CURSOR_RIGHT_BUTTON

wx.CURSOR_SIZENESW

wx.CURSOR_SIZENS

wx.CURSOR_SIZENWSE

wx.CURSOR_SIZEWE

wx.CURSOR_SIZING

wx.CURSOR_SPRAYCAN

wx.CURSOR_WAIT

wx.CURSOR_WATCH

wx.CURSOR_ARROWWAIT

wx.Frame styles

wx.DEFAULT_FRAME_STYLE

wx.ICONIZE

wx.FRAME_SHAPED

wx.CAPTION

wx.MINIMIZE

wx.MINIMIZE_BOX

wx.MAXIMIZE

wx.MAXIMIZE_BOX

wx.STAY_ON_TOP

wx.SYSTEM_MENU

wx.SIMPLE_BORDER

wx.RESIZE_BORDER

wx.FRAME_TOOL_WINDOW

wx.FRAME_NO_TASKBAR

wx.FRAME_FLOAT_ON_PARENT

wx.FRAME_EX_CONTEXTHELP

Standard Colour Database

AQUAMARINE

BLACK

BLUE

BLUE VIOLET

BROWN

CADET BLUE

CORAL

CORNFLOWER BLUE

CYAN

DARK GREY

DARK GREEN

DARK OLIVE GREEN

DARK ORCHID

DARK SLATE BLUE

DARK SLATE GREY

DARK TURQUOISE

DIM GREY

FIREBRICK

FOREST GREEN

GOLD

GOLDENROD

GREY

GREEN

GREEN YELLOW

INDIAN RED

KHAKI

LIGHT BLUE

LIGHT GREY

LIGHT STEEL BLUE

LIME GREEN

MAGENTA

MAROON

MEDIUM AQUAMARINE

MEDIUM BLUE

MEDIUM FOREST GREEN

MEDIUM GOLDENROD

MEDIUM ORCHID

MEDIUM SEA GREEN

MEDIUM SLATE BLUE

MEDIUM SPRING GREEN

MEDIUM TURQUOISE

MEDIUM VIOLET RED

MIDNIGHT BLUE

NAVY

ORANGE

ORANGE RED

ORCHID

PALE GREEN

PINK

PLUM

PURPLE

RED

SALMON

SEA GREEN

SIENNA

SKY BLUE

SLATE BLUE

SPRING GREEN

STEEL BLUE

TAN

THISTLE

TURQUOISE

VIOLET

VIOLET RED

WHEAT

WHITE

YELLOW

YELLOW GREEN

wx.Pen styles

wx.SOLID

wx.TRANSPARENT

wx.DOT

wx.LONG_DASH

wx.SHORT_DASH

wx.DOT_DASH

wx.STIPPLE

wx.USER_DASH

wx.BDIAGONAL_HATCH

wx.CROSSDIAG_HATCH

wx.FDIAGONAL_HATCH

wx.CROSS_HATCH

wx.HORIZONTAL_HATCH

wx.VERTICAL_HATCH

wx.Brush styles

wx.BLUE_BRUSH

wx.GREEN_BRUSH

wx.WHITE_BRUSH

wx.BLACK_BRUSH

wx.GREY_BRUSH

wx.MEDIUM_GREY_BRUSH

wx.LIGHT_GREY_BRUSH

wx.TRANSPARENT_BRUSH

wx.CYAN_BRUSH

wx.RED_BRUSH

CalendarCtrl styles

CAL_SUNDAY_FIRST

CAL_MONDAY_FIRST

CAL_SHOW_HOLIDAYS

CAL_NO_YEAR_CHANGE

CAL_NO_MONTH_CHANGE

CAL_SEQUENTIAL_MONTH_SELECTION

CAL_SHOW_SURROUNDING_WEEKS

CAL_HITTEST_NOWHERE

CAL_HITTEST_HEADER

CAL_HITTEST_DAY

CAL_HITTEST_INCMONTH

CAL_HITTEST_DECMONTH

CAL_HITTEST_SURROUNDING_WEEK

CAL_BORDER_NONE

CAL_BORDER_SQUARE

CAL_BORDER_ROUND

Keycodes

WXK_BACK

WXK_TAB

WXK_RETURN

WXK_ESCAPE

WXK_SPACE

WXK_DELETE

WXK_START

WXK_LBUTTON

WXK_RBUTTON

WXK_CANCEL

WXK_MBUTTON

WXK_CLEAR

WXK_SHIFT

WXK_CONTROL

WXK_MENU

WXK_PAUSE

WXK_CAPITAL

WXK_PRIOR

WXK_NEXT

WXK_END

WXK_HOME

WXK_LEFT

WXK_UP

WXK_RIGHT

WXK_DOWN

WXK_SELECT

WXK_PRINT

WXK_EXECUTE

WXK_SNAPSHOT

WXK_INSERT

WXK_HELP

WXK_NUMPAD0

WXK_NUMPAD1

WXK_NUMPAD2

WXK_NUMPAD3

WXK_NUMPAD4

WXK_NUMPAD5

WXK_NUMPAD6

WXK_NUMPAD7

WXK_NUMPAD8

WXK_NUMPAD9

WXK_MULTIPLY

WXK_ADD

WXK_SEPARATOR

WXK_SUBTRACT

WXK_DECIMAL

WXK_DIVIDE

WXK_F1

WXK_F2

WXK_F3

WXK_F4

WXK_F5

WXK_F6

WXK_F7

WXK_F8

WXK_F9

WXK_F10

WXK_F11

WXK_F12

WXK_F13

WXK_F14

WXK_F15

WXK_F16

WXK_F17

WXK_F18

WXK_F19

WXK_F20

WXK_F21

WXK_F22

WXK_F23

WXK_F24

WXK_NUMLOCK

WXK_SCROLL

WXK_PAGEUP

WXK_PAGEDOWN

WXK_NUMPAD_SPACE

WXK_NUMPAD_TAB

WXK_NUMPAD_ENTER

WXK_NUMPAD_F1

WXK_NUMPAD_F2

WXK_NUMPAD_F3

WXK_NUMPAD_F4

WXK_NUMPAD_HOME

WXK_NUMPAD_LEFT

WXK_NUMPAD_UP

WXK_NUMPAD_RIGHT

WXK_NUMPAD_DOWN

WXK_NUMPAD_PRIOR

WXK_NUMPAD_PAGEUP

WXK_NUMPAD_NEXT

WXK_NUMPAD_PAGEDOWN

WXK_NUMPAD_END

WXK_NUMPAD_BEGIN

WXK_NUMPAD_INSERT

WXK_NUMPAD_DELETE

WXK_NUMPAD_EQUAL

WXK_NUMPAD_MULTIPLY

WXK_NUMPAD_ADD

WXK_NUMPAD_SEPARATOR

WXK_NUMPAD_SUBTRACT

WXK_NUMPAD_DECIMAL

WXK_NUMPAD_DIVIDE

Comments...

I've added a little example extending the wx.TreeCtrl example to create a window with a tree and moveable splitter window at AnotherTutorialTreeCtrlComment. adil hasan

Another tutorial (Phoenix) (last edited 2020-12-31 16:56:00 by Ecco)

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