A Look at wxPython

This article is the first in a series covering wxPython, a library that makes it easy for Python programmers to build graphical user interfaces. It introduces some simple dialogs, explains how to create a simple frame, how to create a menu, and how to add two basic controls to a panel.

Introduction

There are times when tinkering around in a console might suit you and your application nicely, but moving on may suit you nicely as well. This is where graphical user interfaces –- GUIs –- enter the story. Applications like this are often made in languages such as C++, Java and Visual Basic, but Python has the power to handle graphical user interfaces as well. A library called Tkinter is shipped with Python, but a better alternative exists: wxPython. If you’re coming from a C++ background, this name probably sounds familiar. That’s because it’s a wrapper around wxWidgets.

While Tkinter offers only a handful of options, wxPython offers many. You can put almost any widget you can imagine in your Python application, and since it’s Python, it’s extremely easy to do so. We’ll take a look at wxPython in this article, exploring the basics of the library and its benefits.

The first step in learning how to use wxPython is, obviously, obtaining the library. You may obtain it at the official site:

http://wxpython.org

{mospagebreak title=The Basics}

Let’s take a look at the basics of wxPython by creating a simple text dialog. It will ask the user to input a string of text, and it will then print the string, unless the user exited the dialog by clicking the “X” or the “Cancel” button. In that case, we’ll display another message to the user. Here’s the code for our application, complete with comments to explain what we’re doing:

# Here we import wxPython:

from wxPython.wx import *

# Before we create anything, we must create an “App” object:

application = wxPySimpleApp()

# Now we create the dialog:

dialog = wxTextEntryDialog ( None, ‘Enter some text:’, ‘Title Here’, ‘Default text here.’ )

# If the user presses, “OK”, print the value. Otherwise, print another message.

if dialog.ShowModal() == wxID_OK:

   print dialog.GetValue()

else:

   print ‘You did not push the “OK” button.’

# Destroy the dialog

dialog.Destroy()

As you can see, the whole process isn’t very complicated. The only thing to add to the above example is that the first argument passed to wxTextEntryDialog is the parent of the dialog. Since we’re not working with any windows (yet), we pass None.

Note that we mix our primitive GUI with a console. This is not necessary. Instead of printing the resulting message, we can display it in another dialog:

from wxPython.wx import *

application = wxPySimpleApp()

dialog = wxTextEntryDialog ( None, ‘Enter some text:’, ‘Title Here’, ‘Default text here.’ )

if dialog.ShowModal() == wxID_OK:

  

   # Create a “wxMessageDialog” to display the input:

   message = wxMessageDialog ( None, dialog.GetValue(), ‘Title Here’, wxOK )

   message.ShowModal()

   message.Destroy()

else:

   # Create another “wxMessageDialog” to display a simple message:

   message = wxMessageDialog ( None, ‘You did not push the “OK” button.’, ‘Title Here’, wxOK )

   message.ShowModal()

   message.Destroy()

dialog.Destroy()

To get rid of the console completely, save the file with the extension “.pyw” rather than the default extension.

Notice how we pass wxOK as wxMessageDialog‘s final argument. This creates our dialog with only an “OK” button. If we need a “Cancel” button, we can take out wxOK and pass nothing:

from wxPython.wx import *

application = wxPySimpleApp()

dialog = wxMessageDialog ( None, ‘Just a message.’, ‘Title Here’ )

dialog.ShowModal()

dialog.Destroy()

We can also pass wxCANCEL in addition to wxOK:

from wxPython.wx import *

application = wxPySimpleApp()

dialog = wxMessageDialog ( None, ‘Just a message.’, ‘Title Here’, wxOK | wxCANCEL )

dialog.ShowModal()

dialog.Destroy()

As you saw earlier, it is very simple to check whether the user clicked “OK” or not:

from wxPython.wx import *

application = wxPySimpleApp()

dialog = wxMessageDialog ( None, ‘Just a message.’, ‘Title Here’ )

if dialog.ShowModal() == wxOK:

   # User pressed “OK”

   pass

dialog.Destroy()

Of course, we can do more to our simple dialog. Instead of “OK” and “Cancel”, we can display “Yes” and “No”:

from wxPython.wx import *

application = wxPySimpleApp()

dialog = wxMessageDialog ( None, ‘Just a message.’, ‘Title Here’, wxYES_NO )

dialog.ShowModal()

dialog.Destroy()

We can also create an icon. Let’s make an information icon ( “i” ):

from wxPython.wx import *

application = wxPySimpleApp()

dialog = wxMessageDialog ( None, ‘Just a message.’, ‘Title Here’, wxICON_INFORMATION )

dialog.ShowModal()

dialog.Destroy()

A question mark icon is also possible:

from wxPython.wx import *

application = wxPySimpleApp()

dialog = wxMessageDialog ( None, ‘Just a message.’, ‘Title Here’, wxICON_QUESTION )

dialog.ShowModal()

dialog.Destroy()

So is an exclamation mark:

from wxPython.wx import *

application = wxPySimpleApp()

dialog = wxMessageDialog ( None, ‘Just a message.’, ‘Title Here’, wxICON_EXCLAMATION )

dialog.ShowModal()

dialog.Destroy()

If we want to notify the user of an error, it is possible to put an error icon in:

from wxPython.wx import *

application = wxPySimpleApp()

dialog = wxMessageDialog ( None, ‘Just a message.’, ‘Title Here’, wxICON_ERROR )

dialog.ShowModal()

dialog.Destroy()

{mospagebreak title=Creating Windows and Status Bars}

All right. Dialogs are fine to mess with for a while, but let’s move on. (By the way, note that wxPython includes many more dialogs). Let’s create a window:

from wxPython.wx import *

application = wxPySimpleApp()

dialog = wxFrame ( None, wxID_ANY, ‘Title Here.’ )

dialog.Show ( True )

application.MainLoop()

When creating a wxFrame, three arguments are passed, as you can see. The first argument is the parent, which you have already seen. Our window does not have a parent. The second argument is the ID of the object. We don’t need to worry about it in this tutorial –- passing wxID_ANY will work fine. The third argument is, obviously, the title of the window.

Many applications have status bars at the bottom with certain text. We can add a simple one to our application:

from wxPython.wx import *

application = wxPySimpleApp()

window = wxFrame ( None, wxID_ANY, ‘Title Here.’ )

window.CreateStatusBar()

window.Show ( True )

application.MainLoop()

{mospagebreak title=Creating Menus}

One of the uses of a status bar is to display details about a certain menu option. Let’s create a menu for our window. Our menu bar will contain two categories: “One” and “Two”. They will each have four options: “1”, “2”, “3” and “4” and “A”, “B”, “C” and “D”, respectively. Let’s bring our plan to life:

from wxPython.wx import *

application = wxPySimpleApp()

window = wxFrame ( None, wxID_ANY, ‘Title Here.’ )

window.CreateStatusBar()

# Create “One” and fill it with the options

one = wxMenu()

one.Append ( 100, ’1′, ‘This text will display in the status bar.’ )

one.Append ( 101, ’2′, ‘So will this.’ )

one.Append ( 102, ’3′, ‘Option three.’ )

one.Append ( 103, ’4′, ‘Option four.’ )

one.AppendSeparator()

one.Append ( 104, ’5′, ‘This is isolated from the rest.’ )

# Create “Two” and fill it with the options

two = wxMenu()

two.Append ( 105, ‘A’, ‘A.’ )

two.Append ( 106, ‘B’, ‘B.’ )

two.Append ( 107, ‘C’, ‘C.’ )

two.Append ( 108, ‘D’, ‘D.’ )

two.Append ( 109, ‘E’, ‘E.’ )

# Now, we’ll add the menu bar and put in the two categories

bar = wxMenuBar()

bar.Append ( one, ‘One’ )

bar.Append ( two, ‘Two’ )

# Finally, we’ll put in the menu bar

window.SetMenuBar ( bar )

window.Show ( True )

application.MainLoop()

Adding a menu isn’t very hard, is it? The only thing I would like to point out here is the numbers you see passed to Append. Each menu option must have its own unique number, or the menu will not function properly.

If we want to make our menu more complex, we can do so. Execute this code for something more advanced than our last example:

from wxPython.wx import *

application = wxPySimpleApp()

window = wxFrame ( None, wxID_ANY, ‘Title Here.’ )

window.CreateStatusBar()

# Create a top-level menu

parent = wxMenu()

# Create a child menu that will be added to the parent menu

child = wxMenu()

child.Append ( 100, ‘Option 1′, ‘Option 1.’ )

child.Append ( 101, ‘Option 2′, ‘Option 2.’ )

# Add the child menu to the parent menu

parent.AppendMenu ( 102, ‘&ChildtShift C’, child )

# Add another menu

# This menu will contain items that work like radio boxes

radio = wxMenu()

radio.Append ( 103, ‘First’, ‘First.’, wxITEM_RADIO )

radio.Append ( 104, ‘Second’, ‘Second.’, wxITEM_RADIO )

# Add yet another menu

# The options in this menu will behave like checkboxes

check = wxMenu()

check.Append ( 105, ‘Former’, ‘Former.’, wxITEM_CHECK )

check.Append ( 106, ‘Latter’, ‘Latter.’, wxITEM_CHECK )

# Create a menu bar

bar = wxMenuBar()

bar.Append ( parent, ‘Parent’ )

bar.Append ( radio, ‘Radio’ )

bar.Append ( check, ‘Check’ )

window.SetMenuBar ( bar )

window.Show ( True )

application.MainLoop()

{mospagebreak title=Events}

What good is a menu when it doesn’t do anything besides look pretty? Let’s add some real functionality to our menu. As you probably have guessed, wxPython makes this very simple. Let’s combine our knowledge of dialogs with our knowledge of menus. We just have to glue it together. Remember those unique numbers we assigned to each menu item? We’ll use them below:

from wxPython.wx import *

application = wxPySimpleApp()

window = wxFrame ( None, wxID_ANY, ‘Title Here.’ )

window.CreateStatusBar()

# You’ll see the signifigance of “name” in a second

name = ‘John Doe’

# Create a menu

# Nothing new here

menu = wxMenu()

menu.Append ( 100, ‘Text Entry’, ‘Open a text entry dialog.’ )

menu.Append ( 101, ‘Message’, ‘Open a message dialog.’ )

bar = wxMenuBar()

bar.Append ( menu, ‘Options’ )

window.SetMenuBar ( bar )

# Now we’ll make the menu options do something

# First, we’ll define two functions:

def text ( event ):

   global name

   textDialog = wxTextEntryDialog ( window, ‘What is your name?’, ‘Name’, name )

   textDialog.ShowModal()

   name = textDialog.GetValue()

   textDialog.Destroy()

def message ( event ):

   messageDialog = wxMessageDialog ( window, ‘Your name is: ‘ + name, ‘Name’, wxICON_INFORMATION | wxOK )

   messageDialog.ShowModal()

   messageDialog.Destroy()

# We will now attach our functions to our menu

EVT_MENU ( window, 100, text )

EVT_MENU ( window, 101, message )

window.Show ( True )

application.MainLoop()

{mospagebreak title=Some Widgets}

Now let’s add some controls to our window. First, though, let’s shift the structure of our application. Instead of throwing everything in the global namespace, let’s create a class –- a subclass of wxFrame. While we’re add it, how about setting the size of our window?

from wxPython.wx import *

class Window ( wxFrame ):

   def __init__ ( self ):

      wxFrame.__init__ ( self, None, wxID_ANY, ‘Title’, size = ( 350, 350 ) )

      self.Show ( True )

application = wxPySimpleApp()

window = Window()

application.MainLoop()

Now we’re ready. Let’s add a simple button to our window:

from wxPython.wx import *

class Window ( wxFrame ):

   def __init__ ( self ):

      wxFrame.__init__ ( self, None, wxID_ANY, ‘Title’, size = ( 350, 350 ) )

      self.button = wxButton ( self, 100, ‘Click’ )

      self.Show ( True )

application = wxPySimpleApp()

window = Window()

application.MainLoop()

Ugh, it takes up the whole window. This can be fixed by putting it in a panel:

from wxPython.wx import *

class Window ( wxFrame ):

   def __init__ ( self ):

      wxFrame.__init__ ( self, None, wxID_ANY, ‘Title’, size = ( 350, 350 )  )

      self.panel = wxPanel ( self, wxID_ANY )

      self.button = wxButton ( self.panel, 100, ‘Click’ )

      self.Show ( True )

application = wxPySimpleApp()

window = Window()

application.MainLoop()

That’s better. Now let’s add a text box:

from wxPython.wx import *

class Window ( wxFrame ):

   def __init__ ( self ):

      wxFrame.__init__ ( self, None, wxID_ANY, ‘Title’, size = ( 350, 350 )  )

      self.panel = wxPanel ( self, wxID_ANY )

      self.button = wxButton ( self.panel, 100, ‘Click’ )

      self.text = wxTextCtrl ( self.panel, 101, ‘Some text.’, ( 100, 100 ) )

      self.Show ( True )

application = wxPySimpleApp()

window = Window()

application.MainLoop()

Now let’s make our button do something. I won’t get into detail about this, since it’s pretty simple to understand:

from wxPython.wx import *

class Window ( wxFrame ):

   def __init__ ( self ):

      wxFrame.__init__ ( self, None, wxID_ANY, ‘Title’, size = ( 350, 350 )  )

      self.panel = wxPanel ( self, wxID_ANY )

      self.button = wxButton ( self.panel, 100, ‘Click’ )

      self.text = wxTextCtrl ( self.panel, 101, ‘Some text.’, ( 100, 100 ) )

      EVT_BUTTON ( self.panel, 100, self.click )

      self.Show ( True )

   def click ( self, event ):

      message= wxMessageDialog ( self, ‘You clicked the button.’, ‘Clicked’, wxICON_EXCLAMATION )

      message.ShowModal()

      message.Destroy()

application = wxPySimpleApp()

window = Window()

application.MainLoop()

Wrapping Up

So far, you’ve learned a little bit about wxPython. You know how to create two simple dialogs, how to create a simple frame, how to create a menu and how to add two basic controls to a panel. That is all I’ll explain in this article, but wxPython is a very large library, so don’t think that this is it. Dozens of controls, dialogs and frames can be used in your applications –- way more than I can cover in a single article. However, stay tuned. This is definitely not the end.

Google+ Comments

Google+ Comments