Print

Python Programming on Win32
Pages: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12

Where to get wxPython

The latest version of wxPython can always be found at http://alldunn.com/wxPython/. From this site you can download a self-installer for Win32 systems that includes a prebuilt extension module, documentation in HTML help format, and a set of demos.

Also available from this site is a Linux RPM, wxPython sources, documentation in raw HTML, and pointers to other sites, mail lists, the wxPython FAQ, and so forth.

If you want to build wxPython from sources yourself, you also need the wxWindows sources, available from http://www.wxwindows.org/.

Where to go from here

The remainder of this chapter gives a basic introduction to using wxPython, starting with a simple example teaching the basic structure of a wxPython application. We then build a more involved sample that touches on some of the more advanced features of the toolkit, using classes from the Doubletalk financial modeler you're already familiar with.

Using wxPython

We've always found that the best way to learn is by doing and then experimenting and tweaking with what's been done. So download and install wxPython, fire up your favorite text editor[1] and get ready to play along as you read the next few sections.

A simple example

Familiarize yourself with this little wxPython program, and refer back to it as you read through the explanations that follow:

from wxPython.wx import *
 
class MyApp(wxApp):
    def OnInit(self):
        frame = wxFrame(NULL, -1, "Hello from wxPython")
        frame.Show(true)
        self.SetTopWindow(frame)
        return true
 
app = MyApp(0)
app.MainLoop()

When you run this code, you should see a Window appear similar to Figure 20-6.

Figure 20-6. A basic wxPython application

 

The first thing to do is import the entire wxPython library with the from wxPython.wx import * statement. This is common practice for wxPython programs, but you can obviously perform more restrictive imports if you prefer.

Every wxPython application needs to derive a class from wxApp and provide an OnInit method for it. The framework calls this method as part of its initialization sequence, and the usual purpose of OnInit is to create the windows and essentials necessary for the program to begin operation. In the sample you created a frame with no parent, with a title of "Hello from wxPython" and then showed it. We could also have specified a position and size for the frame in its constructor, but since we didn't, defaults are used. The last two lines of the OnInit method will probably be the same for all applications; SetTopWindow method informs wxWindows that this frame is one of the main frames (in this case the only one) for the application, and you return true to indicate success. When all top-level windows have been closed, the application terminates.

The final two lines of the script again will probably be the same for all your wxPython applications. You create an instance of the application class and call its MainLoop method. MainLoop is the heart of the application: it's where events are processed and dispatched to the various windows, and it returns when the final window is closed. Fortunately, wxWindows insulates you from the differences in event processing in the various GUI toolkits.

Most of the time you will want to customize the main frame of the application, and so using the stock wxFrame isn't sufficient. As you might expect, you can derive your own class from wxFrame to begin customization. This next example builds on the last by defining a frame class and creating an instance in the application's OnInit method. Notice that except for the name of the class created in OnInit, the rest of the MyApp code is identical to the previous example. This code is displayed in Figure 20-7.

from wxPython.wx import *
 
ID_ABOUT = 101
ID_EXIT  = 102
 
class MyFrame(wxFrame):
    def _    _init_    _(self, parent, ID, title):
        wxFrame._    _init_    _(self, parent, ID, title,
                         wxDefaultPosition, wxSize(200, 150))
        self.CreateStatusBar()
        self.SetStatusText("This is the statusbar")
 
        menu = wxMenu()
        menu.Append(ID_ABOUT, "&About",
                    "More information about this program")
        menu.AppendSeparator()
        menu.Append(ID_EXIT, "E&xit", "Terminate the program")
 
        menuBar = wxMenuBar()
        menuBar.Append(menu, "&File");
 
        self.SetMenuBar(menuBar)
 
 
class MyApp(wxApp):
    def OnInit(self):
        frame = MyFrame(NULL, -1, "Hello from wxPython")
        frame.Show(true)
        self.SetTopWindow(frame)
        return true
 
app = MyApp(0)
app.MainLoop()
Figure 20-7. A wxPython application with menus

 

This example shows some of the built-in capabilities of the wxFrame class. For example, creating a status bar for the frame is as simple as calling a single method. The frame itself automatically manages its placement, size, and drawing. On the other hand, if you want to customize the status bar, create an instance of your own wxStatusBar-derived class and attach it to the frame.

Creating a simple menu bar and a drop-down menu is also demonstrated in this example. The full range of expected menu capabilities is supported: cascading submenus, checkable items, popup menus, etc.; all you have to do is create a menu object and append menu items to it. The items can be text as shown here, or other menus. With each item you can optionally specify some short help text, as we have done, which are shown in the status bar automatically when the menu item is selected.

Events in wxPython

The one thing that the last sample doesn't do is show how to make the menus actually do something. If you run the sample and select Exit from the menu, nothing happens. The next sample takes care of that little problem.

To process events in wxPython, any method (or standalone function for that matter) can be attached to any event using a helper function from the toolkit. wxPython also provides a wxEvent class and a whole bunch of derived classes for containing the details of the event. Each time a method is invoked due to an event, an object derived from wxEvent is sent as a parameter, the actual type of the event object depends on the type of the event; wxSizeEvent for when the window changes size, wxCommandEvent for menu selections and button clicks, wxMouseEvent for (you guessed it) mouse events, and so forth.

To solve our little problem with the last sample, all you have to do is add two lines to the MyFrame constructor and add some methods to handle the events. We'll also demonstrate one of the common dialogs, the wxMessageDialog. Here's the code, with the new parts in bold, and the running code shown in Figure 20-8:

from wxPython.wx import *
 
ID_ABOUT = 101
ID_EXIT  = 102
 
class MyFrame(wxFrame):
    def _    _init_    _(self, parent, ID, title):
        wxFrame._    _init_    _(self, parent, ID, title,
                         wxDefaultPosition, wxSize(200, 150))
        self.CreateStatusBar()
        self.SetStatusText("This is the statusbar")
        menu = wxMenu()
        menu.Append(ID_ABOUT, "&About",
                    "More information about this program")
        menu.AppendSeparator()
        menu.Append(ID_EXIT, "E&xit", "Terminate the program")
        menuBar = wxMenuBar()
        menuBar.Append(menu, "&File");
        self.SetMenuBar(menuBar)
 
        EVT_MENU(self, ID_ABOUT, self.OnAbout)
        EVT_MENU(self, ID_EXIT,  self.TimeToQuit)
 
    def OnAbout(self, event):
        dlg = wxMessageDialog(self, "This sample program shows off\n"
                              "frames, menus, statusbars, and this\n"
                              "message dialog.",
                              "About Me", wxOK | wxICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()
 
    def TimeToQuit(self, event):
        self.Close(true)
 
class MyApp(wxApp):
    def OnInit(self):
        frame = MyFrame(NULL, -1, "Hello from wxPython")
        frame.Show(true)
        self.SetTopWindow(frame)
        return true
 
app = MyApp(0)
app.MainLoop()
Figure 20-8. The application with an About box

 

The EVT_MENU function called here is one of the helper functions for attaching events to methods. Sometimes it helps to understand what is happening if you translate the function call to English. The first one says, "For any menu item selection event sent to the window self with an ID of ID_ABOUT, invoke the method self.OnAbout."

There are many of these EVT_* helper functions, all of which correspond to a specific type of event, or events. Some popular ones are listed in Table 20-4. See the wxPython documentation for details.

Table 20-4: Common wxPython Event Functions

Event Function

Event Description

EVT_SIZE

Sent to a window when its size has changed, either interactively by the user or programmatically.

EVT_MOVE

Sent to a window when it has been moved, either interactively by the user or programmatically.

EVT_CLOSE

Sent to a frame when it has been requested to close. Unless the close is being forced, it can be canceled by calling event.Veto(true).

EVT_PAINT

This event is sent whenever a portion of the window needs to be redrawn.

EVT_CHAR

Sent for each nonmodifier (Shift key, etc.) keystroke when the window has the focus.

EVT_IDLE

This event is sent periodically when the system isn't processing other events.

EVT_LEFT_DOWN

The left mouse button has been pressed down.

EVT_LEFT_UP

The left mouse button has been let up.

EVT_LEFT_DCLICK

The left mouse button has been double-clicked.

EVT_MOTION

The mouse is in motion.

EVT_SCROLL

A scrollbar has been manipulated. This one is actually a collection of events, which can be captured individually if desired.

EVT_BUTTON

A button has been clicked.

EVT_MENU

A menu item has been selected.

 

Pages: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12

Next Pagearrow