“App’ing up” PyQt… ugh.
One of biggest problems with PyQt is distributing it in a stand-alone package. Even worse… wanting to make your Qt plugins still function (Phonon, jpeg, etc). At work I constantly had this battle, along with my co-worker Tory. She actually has a long-standing issue with this, and had to resort to workarounds or half fixes. Here is Tory’s original post regarding the issue .
I would see an error similar to this when trying to package up and run an app using the Phonon module.
WARNING: bool Phonon::FactoryPrivate::createBackend() phonon backend plugin could not be loaded
Running macdeployqt myAppName.app does add things like the jpeg plugin, but never seemed to fix the Phonon issue. I finally decided to randomly look online for a solution, again, last week. What I found was a partial solution, followed by me trying one more thing and bam…it worked! Video playback from my .app standalone package.
Here is what I did …
(btw you might have to modify the location of the plugin, since I happen to be using OSX)
- In your setup.py file, which is used for py2app, py2exe, or similar… add this to the DATA_FILES list, so that it looks as such:
DATA_FILES = [('phonon_backend',
['/Developer/Applications/Qt/plugins/phonon_backend/libphonon_qt7.dylib'] )]
This will put the phonon backend plugin into the RESOURCES folder in the app. - Package up your application via py2app / py2exe / etc.
- If you are on OSX, use macdeployqt on the app:
>>> macdeployqt myApp.app - Go into the app that was created (show package contents if you are on a mac), and move the phonon_backend directory FROM the Resources directory TO the PlugIns directory (which should be at the same level as Resources).
That should be it!

I get to do a lot of interesting applications at SouthPark. This one in particular was the most challenging use of PyQt that I have experienced to date.
The backstory….
The art department wanted a tool to help them track assigned tasks, the progress, and to share media and notes associated with the tasks. Furthermore, they wanted to be able to skin the interface with custom graphics to make it their own.
Progress…
During the winter break (about a month) I was able to come up with version 1.0 of TaskMonster. It was written in python, using PyQt for the UI, sqlalchemy to talk to the database, and twisted for the client/server communication. Each client app sends messages to a small server daemon which in turn tells the rest of the clients about the updates.
Version 2.0 Alpha…
Tony Postma, from the art department, put together a design in Corel which I could hopefully implement in the UI. It called for the users to be represented as little pods in a circle around the supervisor, Adrien Beard. And each user pod could be clicked and rotated into place, in order to view that persons tasks.
After a bunch of testing I was able to design a rotating widget that could dynamically lay out N widgets around it in a circle, track their position, and jump to any other widget. I was also able to break down the corel->illustrator file, into a combination of SVG and PNG images, and skin the UI via CSS stylesheets.
Its currently an alpha release. I guess I need to really learn how to control the widget painting, to make it faster. Never had to do this much before.
What I came up with… Click here to watch the demo video

You know when you have all these widgets laid out in your class, and you are hooking up all the connections, and you say “Aw dammit I have to subclass QLabel now just so make it ignore blahEvent”? You end up with all these little widget subclasses, where all they are doing is ignoring an event.
I noticed I was doing this a few times, in more than one of my classes, and finally got annoyed for the last time. I figured there had to be a simple way of just overloading the method on the normal object when I create an instance. Fortunately python considers everything objects and pretty much anything can be changed. So I did this:
myLabel = QLabel() myLabel.mousePressEvent = lambda event: event.ignore()
Magic.
I have also had to make clickable widgets, such as QLabel:
myLabel = QLabel()
myLabel.mousePressEvent = lambda event: myLabel.emit(SIGNAL("clicked"))
Or if you had to do more than just a single statement:
myLabel = QLabel()
def clickedEvent(event):
myLabel.emit(SIGNAL("clicked"))
# do other stuff
# do stuff
event.accept()
myLabel.mousePressEvent = clickedEvent
I like this better than piling up subclasses that don’t do much.

