PDA

View Full Version : py2app-deployed PyQt app -- throws QObject threading error



tory108
16th January 2009, 22:38
Hi, everyone,

This forum has been wonderfully useful in my attempts to deploy a phonon-using python app for the Mac. I hope I can get some advice on this next error.

I have a music player script, very strongly based on the Qt 4.4.3 Music Player example here (http://doc.trolltech.com/4.4/phonon-musicplayer.html) (although this example is in C++ and mine is in python, obvy).

When I run the script locally, it works as expected -- I can double-click on a track, or select the track and click the "play" button, and I hear the track's audio, the seekSlider advances, and the digital display advances.

However, when I run the app created by py2app -- via the following command:

python setup.py py2app --includes sip --extension .app -O2

the resulting app plays the audio, but the seekSlider does not advance, the digital display does not advance, and I receive the following error in the console:


QObject: Cannot create children for a parent that is in a different thread.
(Parent is Phonon::AudioOutput(0x13e48080), parent's thread is QThread(0x1e9a20), current thread is QThread(0x13e4dea0)
QObject: Cannot create children for a parent that is in a different thread.
(Parent is Phonon::MediaObject(0x13e47e00), parent's thread is QThread(0x1e9a20), current thread is QThread(0x13e4dea0)
QObject::startTimer: QTimer can only be used with threads started with QThread
QObject::startTimer: QTimer can only be used with threads started with QThread
QObject: Cannot create children for a parent that is in a different thread.
QObject: Cannot create children for a parent that is in a different thread.
(Parent is Phonon::MediaObject(0x13e482c0), parent's thread is QThread(0x1e9a20), current thread is QThread(0x13e4dea0)
QObject::connect: Cannot queue arguments of type 'MediaSource'
(Make sure 'MediaSource' is registered using qRegisterMetaType().)
...


I do not do any threading myself, so I'm not sure how to persuade a wrong thread to be a right one.

I am now doing the following phonon object instantiations in __init__()

self.ui.mediaObject = Phonon.MediaObject(self)
self.ui.audioOutput = Phonon.AudioOutput(Phonon.MusicCategory, self)
self.ui.metaInformationResolver = Phonon.MediaObject(self)

although it doesn't seem to be making much a difference from the old way I was doing it, which is this:

self.ui.mediaObject = Phonon.MediaObject()
self.ui.audioOutput = Phonon.AudioOutput(Phonon.MusicCategory)
self.ui.metaInformationResolver = Phonon.MediaObject()


I have also tried mediaObject.moveToThread(self.thread()), to no avail. It actually appears that mediaObject.thread() == self.thread().


I am using Mac OS X, Qt 4.4.3, python 2.6.

Any guidance you can provide would be deeply appreciated. I feel like I'm inches away from success! :D

tory108
20th January 2009, 02:25
All right -- having re-implemented the seek functionality in my own code, I have finally hunted down the source of the threading error.

The problem is that the metatype of an object must be registered before it can be queued.

I see plenty of documentation for how to do this in Qt/C++, but for the life of me I cannot understand how to register a metatype in PyQt/Python.

http://doc.trolltech.com/4.4/qmetatype.html

What is the equivalent of qRegisterMetaType()? And where?


I realize this is now more of a PyQt problem than a Qt problem, but I am at my wits' end, and I begin to feel like I'm throwing good time after bad, so to speak, and will soon have to move on to other projects. Any help would be deeply appreciated.

riklaunim
20th January 2009, 10:42
Well, I used:
python setup.py py2app --packages PyQt4
And it build the app :)

tory108
20th January 2009, 19:42
Okay. For what it's worth, my research indicates that this is all it takes to register a metatype:

registerMe = QtCore.QVariant(Phonon.MediaSource(None))

Apparently what it's doing is registering a class that DOES NOT have a matching C++ class, so that it can be used by C++ methods.

There is some information about this in the PyQt4 docs (unfortunately not online) in section 4: Python Objects and QVariant. An excerpt:

4 Python Objects and QVariant

Qt uses the QVariant class as a wrapper for any C++ data type. Support for new data types (ie. new C++ classes) can be added by registering those types. PyQt automatically registers Python types so that instances of those types can also be wrapped as a QVariant and passed around Qt's meta-object system like any other type.

...

PyQt also provides an overloaded version of the QMetaType.type() static method that takes a Python type object as its single argument. This returns the integer storage type that the Python type is registered as.


So I am no longer getting the "Make sure 'MediaSource' is registered using qRegisterMetaType()" error.

NOW I am getting a "Make sure 'QMultiMap<QString, QString>' is registered using qRegisterMetaType()" error.

The good news is, this definitely looks like I'm on the right forum. The bad news is, why on earth is Qt complaining about the registration of its own class?

Furthermore, where is QMultiMap? Every attempt I have made to manually register QMultiMap generates compile-time "module/attribute not found" errors:

registerMe = QtCore.QVariant(QtCore.QMap.QMultiMap()) -----> "'module' object has no attribute 'QMap'"



In fact, I cannot even manually import QMultiMap according to where Qt's documentation says it is:

from PyQt4.QtCore import QMultiMap ------> "cannot import name QMultiMap"
from PyQt4.QtCore.QMap import QMultiMap ----> "no module named QMap"
from PyQt4.QtCore import QMap ------> "cannot import name QMap"


Thoughts? Notions? Wild ideas?

The hunt continues...

tory108
20th January 2009, 20:16
QMultiMap appears to be created in sipphonon modules within phonon. I don't have the wherewithall to register these classes' metatypes, and I'm not even sure doing so is barking up the right tree.

I'm going to chalk this up to the newness of phonon in Qt4, and the additional variable of PyQt on top of it. The embedded class in phonon and its obfuscation from python seems to be the problem.

For now I am ending my pursuit.

I will post if there's an update or solution, and I hope you will do the same.