I have a method in an object derived from QPushButton that is supposed to change the background color of the button when it receives a status update from a sub-process over QtDBus.
def setStatus( self, test, status, init=False ):
"""
Update status for specified test.
Parameters:
-----------
test: str
String ID of test to set status for.
status: str
String ID of new status.
init: bool
Whether status map is being initialized.
"""
sts = self.status_dict[ status ] # validate status
if init or self._status[ test ] != sts.name: # check that it's actually changed
self._status[ test ] = sts.name
if test == current_test: # Update UI only if test matches current view
self.setStyleSheet( "background-color:{};".format( sts.color ) )
self.setText( "{}: {}".format( self._NAME, sts.desc ) )
self.update()
self.status_changed.emit()
I know that it enters the if test==current_test
loop, and returns successfully.
Also I overrid the paintEvent method to print a message whenever a paint event occurs on this widget. However, the call to update() never triggers a paint event. Replacing it with self.paint()
has no effect either.
This method is called from the object's constructor also, and it works as expected. Also, if I set it to be called every time the button is clicked it also works.
Are there conditions under which update and repaint are ignored. I couldn't find anything in the Qt documentation.
Update
I determined that the sub-process that sends the message over DBus, also receives it. So the message never makes it to the main process, where the QT GUI event loop is running. That's why the UI isn't updated.
The sub-process is spawned after the QDBusAbstractAdapter instance is created and registered, so a copy exists in the same sub-process as the QDBusAbtractInterface. So the interface is sending messages to the adapter in the same process.
The subprocess runs a tornado IOLoop, listening to ZMQStreams, instead of a Qt event loop. So I don't know what's triggering the QtDBus adapter slots.
I can think of a few possibilities of what's happening:
The Qt event loop uses the Tornado IOLoop underneath, so the the QtDBus adapter is already registered with tornado when the sub-process is spawned.
When the Qt event loop is started in the main process, it somehow also starts in the sub-process.
Calling the QtDBus adapter slots on the QtDBus interface starts a temporary Qt event loop.
Anyways, without really knowing what's going on under the hood, the best solution, I think, is to start the sub-processes before the QApplication is created. Then have them listen for a signal from the main process to start their main event loops, once the necessary information is available to initialize them.