Graphical Toolkits for OS X: wxPython
Pages: 1, 2
Let's go through this sample code line by line to make sure we understand what is happening here. First, we tell the computer where the Python interpreter is located on the shebang line, the first line of the program. Your pythonw binary might live in another place, but that is unlikely unless you've moved it yourself. The second line is a Python directive telling Python to import the wx module, which is the wxPython GUI code. The third line instantiates a new app from the wxPython module called wx.PySimpleApp.
The fourth line instantiates a frame, which is really the "window," and passes three arguments to this object. Note if you change the text "Hello World," you will see your changed text in the title bar of the window when you rerun the simple program. The fifth line shows the frame by calling Show like this: frame.Show(True), and the last line fires up the entire program by saying "run the main loop" with app.MainLoop().
Now let's actually do something with our program to make it a little more than just a toy. For this article we are going to build a small application that searches your Apache log file to see how many Firefox and Safari browsers have come to your web site. It is a cursory program, just designed to show how to create dialogs and buttons and to bind those buttons to events. If you were writing a real application, you would include error checking and lots of other things that we have not included here.
Our program, called browsers.py, begins with the familiar shebang line and imports the wx classes from the wx module. We declare our variables and open our log file on line 11. Line 12 begins iterating over the file and the if control says if we find a string like "Firefox" then we increment our variable, and we do this with the string "Safari" as well. From this little Python snippet we get our values, then we incorporate these on line 19, and one line later, we close the file.
#!/usr/bin/env pythonw
import wx
# global variables need to be declared here
foxes = 0
saf = 0
# your apache log file may be located somewhere else
fil = open('/var/log/httpd/access_log', 'r')
for line in fil:
if 'Firefox' in line:
foxes = foxes+1
elif 'Safari' in line:
saf = saf+1
# message contains the result of the above code
message = " we have %d Firefox and %d Safari browsers." % (foxes, saf)
fil.close()
# begin wx code
class MyPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, -1)
# our central button
b = wx.Button(self, -1, "Click to search log file")
# bind the button to an action, in this case OnClick
b.Bind(wx.EVT_BUTTON, self.OnClick)
Sizer = wx.BoxSizer(wx.VERTICAL)
# by adding a stretchable spacer above and below we center the button
Sizer.Add((1,1), 1) # this adds a one by one pixel spacer
# but the "1" means that it has a stretch factor of 1
Sizer.Add(b, 0, wx.ALIGN_CENTER) # the "0" means it won't stretch
Sizer.Add((1,1), 2)
# try changing the stretch factors, and see what you get.
self.SetSizer(Sizer)
def OnClick(self, event):
msgdialog = wx.MessageDialog(self,message,style=wx.OK)
msgdialog.ShowModal()
class MyFrame(wx.Frame):
def __init__(self, parent=None, id=-1, title='Apache log file search',
pos=wx.DefaultPosition, size=(200, 200)):
wx.Frame.__init__(self, parent, id, title, pos, size)
panel = MyPanel(self)
class App(wx.App):
def OnInit(self):
frame = MyFrame()
frame.Center()
frame.Show()
self.SetTopWindow(frame)
return True
def main():
app = App()
app.MainLoop()
if __name__ == '__main__':
main()
Line 23 begins our use of the wx module. First we start by creating a panel appropriately named MyPanel, and the class definition is done on the following lines. On line 28 we have our button defined with the text string "Click to search log file" as the button's text. We then bind this button on the next line to the code defined as "self.OnClick". This is important, since it means that now when someone clicks on the button, code bound to "OnClick" gets run. In our case this begins on line 43, below "def OnClick", and it essentially creates a message dialog and shows that dialog.

Figure 2. The results dialog box
We skipped over some code with comments that helps position our windows and frames and creates space within them. Most of the code and comments come from a program in the wxPythonDemo zip file, which contains lots of excellent sample code to help you get started.
Finally the rest of the code in our program does Python magic that involves inheriting class objects and bringing those objects to life via object calls. You can read more about classes on Python's web site, python.org, as well as on the wxPython site. As you progress and start to feel the need to take greater advantage of the framework and packaging that Apple provides, you will want to read more at Apple's ADC site as well (click on the link that says "Software Delivery Guide"). You may also want to take a look at the wxPython by Example (Manning Publications).
I hope you enjoyed this article. Stay tuned as we check out Qt and GTK+!
Jeremiah Foster fell in love with the Mac years ago. One day, when his new computer had an application called "Terminal," his life was changed. Some years and UNIX certification later, he is still in love with his Mac.
Return to Mac DevCenter.
You must be logged in to the O'Reilly Network to post a talkback.
Showing messages 1 through 16 of 16.
-
Request: Mixing Qt and Cocoa?
2007-05-16 06:44:17 GeoffHutchison [Reply | View]
-
Request: Mixing Qt and Cocoa?
2007-06-18 10:30:50 ghiebert [Reply | View]
I've been playing around with Qt for the past week, after some interest was shown at work of moving our MFC- and Delphi-based code over to Qt.
One part of our code is a set of about 150 different "settings" dialogs, which can be accessed in any applications as modal dialogs through a simple function call. Up to this point, this functionality is available only to Windows users, even though we provide our product on five other platforms.
I had no real difficulty in bringing a Qt dialog up inside a Cocoa application and having it active at the same time as the main Cocoa app. There were just a few issues to take care of:
1) I had to call "qt_mac_set_native_menubar(false)" at the right point to prevent Qt from taking over my application's menu bar.
2) The Qt event loop has to occur in the same thread as the main Cocoa event loop, from what I can tell. For this, I just scheduled an NSTimer to call QApplication::processEvents() periodically from the Cocoa application's run loop, in place of calling myQtApp.exec(). (I guess there'd be no need to even do this if I restrict my calls to use modal Qt dialogs.)
There are still issues with my work: I haven't done any intensive testing of the setup, and I need to find a way to get proper Carbon window references for the Qt windows if I want to get fancy, for example. However, initial results are very encouraging towards bringing Qt components into my Cocoa app in some form. -
Request: Mixing Qt and Cocoa?
2007-05-17 04:38:43 Jeremiah Foster |
[Reply | View]
Thank you for the comment. I am glad you find the article useful, at least I hope it was useful, and yes, I am going to be covering Qt shortly.
As far as combining the Cocoa and Qt systems I am a little skeptical. Could you explain more about how you would combine the two? Using Cocoa you can access Quartz and Core Foundations of the OS directly in an efficient manner which would obviate the need to Qt. But perhaps you have some Qt code that you want to use on the OS X platform - in that case I would look and see if you can use Qt and Objective-C together. Then you can have the cross platform windowing of Qt and the logic in Obj-C. If you intend to use that on another platform you need to make sure Obj-C is available on your chosen platform, which I think is available under Linux but I am unsure about Windows.
Regards,
Jeremiah
-
Nice article but misleading code structure
2007-05-07 07:51:53 strogon14 [Reply | View]
Nice article with a good overview!
Looking at the longer log file analyzing example, I find it a bit problematic from a didactic point of view that the button says "Click to search log file" although the log file has been already parsed by the time the dialog is shown.
An important aspect of GUI programming are callbacks and event-driven programming. So actions in your program should only be carried out, when the user has requested them (e.g. by clicking a button). Or the button should be labeled "Show log file statistics".
In a nutshell, put the log file parsing in a function and a call to it in the "onClick" method.
-
Nice article but misleading code structure
2007-05-07 07:56:03 Jeremiah Foster |
[Reply | View]
Hi there,
Thanks for the comment. You are absolutely right, I need to fix the messaging and the buttons. I will do that in the next version. :)
Regards,
Jeremiah
-
The GUI toolkits
2007-05-05 17:37:34 interprocess [Reply | View]
Do any of the GUI toolkits that you're going to cover work in X11? Can I write a GUI program that executes on my server and displays on user's desktop boxes when they SSH into the server vi the X11.app and execute the program? I've tried with Apple's installs of Tcl/Tk and Python and they won't remote display.
Roger
-
The GUI toolkits
2007-05-07 05:03:05 Jeremiah Foster |
[Reply | View]
Hey Roger,
1. Yes, I am about to publish (in the next week or so) an article on GTK which uses X11 from Apple.
2. Yes you can write server programs that show up on the desktop through ssh. The trick is to make sure X11 is running on the users desktop and to pass the -X (uppercase x) to ssh, like this;
ssh -X your.server.name
Then run the program, like this;
./my_X_app
3. Are you passing the -X switch when you ssh in? Double check you X11 confiiguration and you X windows configuration, it often requires some tweaking because of its default settings. That is to say, you may need to explicitly inform both the server and the client that exporting / importing X windows is allowed.
Hope that helps,
Jeremiah
-
The GUI toolkits
2007-05-08 08:08:32 interprocess [Reply | View]
Jeremiah,
I'll admit that I hadn't tried the -X switch for ssh. I tried, with ssh -X both a python script (that works fine on a Linux) and a compiled program. The compiled program displayed remotely fine, but the script didn't. These are the same results that led me to post the comment. I haven't been able to get Python or Tcl/Tk to display remotely from OSX (10.4.7 server, 10.4.9 client).
Have you actually run your example scripts remotely? I would REALLY like to get OSX to behave like a real Unix.
Roger
-
The GUI toolkits
2007-05-08 10:13:08 Jeremiah Foster |
[Reply | View]
OS X _is_ a real UNIX, plus a lot, lot more. The problem is, UNIX is very flexible and has a steep learning curve. You are running into the joys of X windows programming and X is a huge application which requires a bit of patience I'm afraid.
As to your specific problem - do you want to run a script on one Mac machine from another Mac? If you are just running a python script, they do not have graphical user interfaces by default. Check to make sure it is a calling a windowing toolkit first. If it does not, you will never see a window when running the script.
If your python application uses Tk as a graphical toolkit then you should be able to see it graphically. First, make sure you are running X windows on the client. This is done through Apple's X11 application available through XCode and the Apple Developer Center. You have to launch X11 first, Apple does not use X11 by default, they have their own proprietary system called Aqua. Once X11 is launched, use the terminal to shell into your remote server with the -X switch. Then run your application. This works for me from a Mac mini core duo to a Ubuntu box, both running X Windows.
You can view a screen dump of ssh -X in action here showing Evolution running under X11 with Apple's clock floating on top of it. Pretty slick! :)
http://jeremiahfoster.com/screen_dump.20070508.tiff
So carefully make sure you have X11 running on _both_ machines, that X windows are exported correctly, that your script is in fact calling a graphical toolkit, and that you have fixed any error message X windows may be throwing.
Good luck,
Jeremiah -
The GUI toolkits
2007-05-19 19:10:24 interprocess [Reply | View]
OS X _is_ a real UNIX, plus a lot, lot more.
Uh, you mean a lot less, don't you?
The python (and wish version) of the scripts run fine when invoked from X11 locally. When someone ssh's into the machine from the X11.app, regardless of ssh args, and invokes the script the same way, the script will only display on the machine that's executing the script, not the user's machine.
I had thought that the problem was between scripts/compiled programs, but the compiled program (FlashNet backup/archive) software had installed it's own X11 library in /usr/local/lib. I just found it this past week.
Try reversing your experiment. Put the script on the Mac mini and get it to display on the Ubuntu box. It'll work fine with the script running on the Linux box and displaying on the mac, but when the mac executes the script, the wheels fall off.
I'm not aware of having to call a window manager explicitly in a Python script. TBH, I thought that that was handled when I imported Tkinter:
from Tkinter import *
Roger
-
OS Confusion
2007-04-27 15:02:06 jwilcox [Reply | View]
I'm confused a bit by what I read in your article and on the wxPython site. I'm running OS 10.4.9, but on a PPC machine. Both your article and the site seem to say that I need to be running on an Intel machine in order to use the 10.4 Universal version. Am I misreading or misinterpreting what I'm seeing?
I'd like to try using wxPython, but won't be upgrading to an Intel-based Mac for another several months.
Thanks,
Jerry -
OS Confusion
2007-05-02 02:30:40 Jeremiah Foster |
[Reply | View]
The short answer is yes, it will work on a PPC machine.
The long answer is you need to determine what version of python you are running, then download the appropriate binary for your platform and version of python. I strongly recommend using the binaries already made on the wxPython web site, (http://www.wxpython.org/download.php#binaries) (scroll down past the Windows binaries to find the Mac stuff.)
Use the "Universal" binary for your PPC machine, like Apple says: "When you see the Universal symbol on Mac applications, that means they're made to run on both Intel- and PowerPC-based Mac computers."
Hopefully that will work for you!
Regards,
Jeremiah
-
How about Tk?
2007-04-24 11:11:17 kevin_walzer [Reply | View]
Please consider Tk as a subject for discussion. It's just as portable and widely used as Qt and wxWidgets, has bindings to Python, Ruby, Tcl, and Perl (via the Tcl::Tk module), and it has the advantage (unlike Gtk) of having a mature Aqua port. -
How about Tk?
2007-04-25 00:56:45 Jeremiah Foster |
[Reply | View]
Hey Kevin,
I most certainly will consider Tk. I will bring this up with the O'Reilly folks.
Jeremiah






I'm currently working with Qt/Mac and wonder about mixed Qt and Cocoa applications. So if you can point me towards any docs on that, or will cover it in your series, please let me know.
Thanks!