How to check main event loop is running?
-
Hello there,
I need to perform some action with X11, to manage a window created with PyQt4. This action cannot be done before the event-loop has begun, and it has to be done asap after the window has been painted on the screen.
I managed to do this already by launching a QThread in my topmost widget's constructor. The QThread will keep polling until the window is hosted by X Window Manager, and then it performs the actions i need it to do.
However, i thought it'd be nicer to use event-handling rather than event-polling. So i would like my top-level QWidget to receive a signal as soon as the event-loop begins. I've understood that using postEvent() would be useful since the event will be released as soon as the event-loop will begin. But i am not sure yet as to how i should use that.For now i call the postEvent in the main function like so:
@app = QtGui.QApplication(sys.argv)
def main():
widget = MyWidget()
widget.show()
# now i assume this should successfully post the event:
# i chose the ApplicationActive event, is it correct?
app.postEvent(widget, QtCore.QEvent(QtCore.QEvent.ApplicationActivate))
# then i connect the event to the widget:
widget.connect(app, QtCore.SIGNAL('ApplicationActivate'),
widget, QtCore.SLOT('on_loop')) # the on_loop is my widget's callback
sys.exit(app.exec_())@In the Widget definition, the callback is defined so:
@def on_loop(self, event): print 'event received is:', event@
Of course, it doesn't work, otherwise i wouldn't be here :)
I'm new to Qt4, not very familiar with signal-slot yet. Another idea i got was perhaps to send the event from my widget constructor, to itself. But i'm again unsure as to how i should implement that.I'd like some guidance, thanks :)
Benjamin
-
I'm usually using QTimer::singleShot() to postpone actions until the event loop is running (and iddle;).
-
Yep, it's what i did, but with a QThread and a while loop. But i wanted to find a more secure way to do that.
-
First of all a event is not a signal. You can not connectec a Event with slot.
To intercept the event you need to reimplement the function:
'event (QEvent e) ' on your QWidget class. then you can check if the event received is the event which you have sent. -
Another way to know when your widget was showed is re implement the function: showEvent (QShowEvent event ).
-
@Renato: the QShowEvent() is reveived before the window is actually hosted on X. I'll stick the QThread technique which works anyway. At least i've learnt something about event handling :) Thanks.
-
unclewerner is right, use the static method "QTimer::singleShot() ":http://doc.qt.nokia.com/4.7/qtimer.html#singleShot. Once it fires, it calls the slot given in the arguments:
Supposed (from your Python code), you want to call slot on_loop() in object widget once the event loop runs, add this code somewhere in your app:
@
QTimer::singleShot(0, widget, "on_loop");
@This all works without threads and sending events manually.
-
@ unclewerner & @ Volker: you seem to prefer QTimer to QThread: is there any advantage using one or the other? is QTimer not a thread with a loop?
-
Timers are processed in the event loop, so the slot will be called once the event loop is running. No Threads needed.
-
[quote author="jesuisbenjamin" date="1307145093"]@ unclewerner & @ Volker: you seem to prefer QTimer to QThread: is there any advantage using one or the other? is QTimer not a thread with a loop?[/quote]
Why do it complicated, when there is a simple solution? You can easily shoot yourself into the foot with a QThread, but it's hard with a QTimer. I don't care about the actual implementation of QTimer's singleShot - it just works.
But if you prefer to implement a QThread based code with some 10s of lines, compared to a one liner... it's your choice.