Search code examples
qtpysidegevent

How to trigger aboutToQuit signal manually in PySide


I'm trying to create a gevent-supported PySide main event loop, based on someone else's code. The following code is using original .exec_() method and running correctly:

...

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    win = MyGuiClass()
    win.ui.show()

    def on_exit(): 
        print "bye..."

    app.aboutToQuit.connect(on_exit)
    app.exec_()

When I click the X button in the main window, on_exit() function is called and bye... string is printed to the console as well.

For the Gevent support, I needed to insert a gevent.sleep(0.01) somewhere inside app.exec_() loop, so I defined the following function:

def wait_app(app):
    app_is_running = True
    while app_is_running:
        app.processEvents()
        gevent.sleep(0.01)

and then changed the original code as follows:

...

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    win = MyGuiClass()
    win.ui.show()

    def on_exit(): 
        print "bye..."

    app.aboutToQuit.connect(on_exit)
    wait_app(app)

Then the Gui application runs perfectly as before, and Gevent based greenlets work in parallel as expected.

Only problem is that when I click the X button on the main window, the Qt application terminates (the window is closed) but the on_exit() function is not called, thus remaining greenlets are left working. How can I manually detect if main window's X button's click event via QtGui.QApplication() (the app) object?

Edit

Considering the suggestion in the accepted answer, the working implementation is as follows:

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)

    timer = QtCore.QTimer()
    import gevent
    def gevent_loop():
        gevent.sleep(0.01)
        timer.start(0)
    timer.timeout.connect(gevent_loop)
    timer.start(0)

    win = test()
    win.ui.show()
    app.exec_()

Edit 2

Here is an example application: https://github.com/ceremcem/weighing-machine-testing


Solution

  • The QCoreApplication::exec() method itself is responsible for emitting the aboutToQuit signal (at least, as of Qt 4.x). Since you are bypassing exec() with your own simple event loop, this signal is never emitted.

    Rather than re-implement exec(), the QCoreApplication documentation recommends a different approach:

    To make your application perform idle processing (i.e. executing a special function whenever there are no pending events), use a QTimer with 0 timeout.

    I don't know anything about Gevent, but you could try using a timer to trigger a call to gevent.sleep(0.01) through each run through the event loop. That way, you can be sure that you aren't circumventing any built-in behaviors implemented by exec().