1

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:

  1. 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.

  2. When the Qt event loop is started in the main process, it somehow also starts in the sub-process.

  3. 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.

orodbhen
  • 2,644
  • 3
  • 20
  • 29
  • Show `paintEvent` implementation. – Pavel Strakhov Aug 05 '15 at 23:59
  • I'm only using paintEvent to track when a paint event occurs for debugging. It just prints a message, and then calls paintEvent of the super object. The problem existed previous to overriding paintEvent. – orodbhen Aug 06 '15 at 01:44
  • Maybe related questions in C++: [update() or repaint() fails to trigger paintEvent()](http://stackoverflow.com/questions/2274512/update-or-repaint-fails-to-trigger-paintevent) and [Qt update() doesn't work](http://stackoverflow.com/questions/22900106/qt-update-doesnt-work). – Mel Aug 06 '15 at 07:58
  • I suggest that something may be wrong with your `paintEvent` declaration and it prevents pyqt from recognizing it as virtual function reimplementation. – Pavel Strakhov Aug 06 '15 at 12:58
  • Commenting out paintEvent has no effect. The widget is updated when called from the main process, but when it's received over DBus there's no change. – orodbhen Aug 13 '15 at 18:07
  • I figured out that setStatus isn't ever running in the main process. I've updated the question with the additional information. – orodbhen Aug 14 '15 at 03:23

0 Answers0