This month I've been looking at another Python window/graphics system called PyQt. PyQt is a Python interface to the Qt interplatform window/graphics system from Trolltech in Norway. Like WxPy (see last month), PyQt is a wrap of a C++ class library which was originally developed for Windows, and then Unix, and finally the Mac. PyQt is somewhat bigger and more complicated than WxPy, a bit more involved to install, and has poorer documentation. Nevertheless, PyQt seems to work OK and does many (or more) of the same things that WxPy does.
For example, both systems are based on event-driven C++ application cores that take control of the process and make calls to Python code to handle user and system events. Once launched, both programs sit in an infinite loop looking for events placed in a queue, and make calls to C++ and Python code which has been registered to specific GUI classes and events in order to provide the program's functionality. This is also the way that X-Windows and native Mac programs work, and is a well-established programming paradigm. However, one consequence of this paradigm is that linear, procedural, programs such as those usually written in Basic or Fortran (e.g.) cannot be used, since once the program enters the main event loop it (almost) never returns. Therefore special techniques must be used in order to perform linear data processing, or to prevent a linear sequence of steps from permanently blocking once the event loop is operating. This issue will be addressed a bit further down on this page, when I demonstrate a simple server program for processing graphics operations from one or more non-blocking interactive Python sessions.
Overall I might have a slight preference for WxPy over PyQt, because WxPy is easier to install, simpler and easier to use, and has much better documentation. For example, there is a WxPy book. A PyQt book is supposed to come out sometime in the fall/winter of 2007. Also, wxWidgets is a free collaborative project, while Qt is an expensive commercial product. Nevertheless, both PyQt and WxPy seem to work well, and I have no serious objection to writing GUI programs using either of them. It may become clearer with time which system is better suited to our needs, but for now I am happy to use either.
Windows and text:
More complicated GUIs:
An interface layout program:
PyQt also supports GL graphics. However, to run GL code under either PyQt or WxPy, PyOpenGL is required, which has lots of files and prerequisites to download and install. I'll eventually tackle this process, if we need 3d surface plots in Python.
Zooming and scrolling:
Variable image shape:
return wx.ImageFromData(fitsArray.shape, fitsArray.shape, byteArray.tostring())
However, if one attempts to create a QPixmap using a similar construct:
return QtGui.QPixmap.fromImage(QtGui.QImage(byteArray.tostring(), ndArray.shape, \ ndArray.shape, QtGui.QImage.Format_RGB32))
the resulting pixmap is blank. This is because the .tostring() result is not bound to a Python variable, and the data is deleted before the new pixmap can be displayed. The workaround is to create an intermediate Python variable to reference the .tostring() result, and pass that variable to the QImage constructor:
# Pixmap data must have a Python reference, or it will be deleted! byteString = byteArray.tostring() # Create QPixmap from byte buffer print 'Creating pixmap from buffer' return QtGui.QPixmap.fromImage(QtGui.QImage(byteString, ndArray.shape, \ ndArray.shape, QtGui.QImage.Format_RGB32))
In the server example below, in order to create multiple image windows, a Python variable which references a list of all windows must be maintained:
# Must have this to keep Python references to Qt objects, or they will disappear! windowlist =  ... # Create new image window using previously defined class imageViewer = plotimage.ImageViewer(sessions, fname, min, max) # Add Qt data to Python list, or it will vanish! windowlist.append(imageViewer)
If each newly created window is not added to this list, it will be deleted before it can appear on the screen. These are just two examples of the memory-related 'gotchas' involved in PyQt programming. WxPy does not have this problem.
Here is an example of using the server and client to display some images. The server is running in the left shell window, and the client is running in the right shell window:
Multiple server connections can be opened from the same, or different Python sessions. Each new connection forks a new process of the server program:
Next month the server will be enhanced to accept binary data from the client, and to create additional plot types. The client protocol will be packaged as objects so that the server and remote data appear to be part of the locally executing Python program. Note that the server can be run on the same computer as the client, or across the network, yielding a true distributed programming model.
İSky Coyote 2007