Python Programming on Win32 using WxPython
Pages: 1, 2, 3, 4, 5
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 trueapp = MyApp(0)app.MainLoop()
When you run this code, you should see a Window appear similar to Figure 20-6.
|
|
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 = 101ID_EXIT = 102class 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 trueapp = MyApp(0)app.MainLoop()
|
|
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 = 101ID_EXIT = 102class 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 trueapp = MyApp(0)app.MainLoop()
|
|
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.
|
Event Function |
Event Description |
|---|---|
|
|
Sent to a window when its size has changed, either interactively by the user or programmatically. |
|
|
Sent to a window when it has been moved, either interactively by the user or programmatically. |
|
|
Sent to a frame when it has been requested to close. Unless the close is being forced, it can be canceled by calling |
|
|
This event is sent whenever a portion of the window needs to be redrawn. |
|
|
Sent for each nonmodifier (Shift key, etc.) keystroke when the window has the focus. |
|
|
This event is sent periodically when the system isn't processing other events. |
|
|
The left mouse button has been pressed down. |
|
|
The left mouse button has been let up. |
|
|
The left mouse button has been double-clicked. |
|
|
The mouse is in motion. |
|
|
A scrollbar has been manipulated. This one is actually a collection of events, which can be captured individually if desired. |
|
|
A button has been clicked. |
|
|
A menu item has been selected. |
