[PyQt] C++ destructors and PyQt?

Bryan A. Jones bjones at ece.msstate.edu
Mon Nov 3 21:59:49 GMT 2014


All,

I’m confused when it comes to the proper way to mesh Qt’s model of creating
a tree of parented objects which destroy themselves when no longer used
with Python’s “delete it when I feel like it” garbage collector. In
particular, I’d like to shut down threads when the underlying Qt objects
are destroyed, but I can’t figure out how to do that. Any advice and wisdom
would be appreciated. I've attached same code with my thoughts.

Bryan

# Test program to ask about destructors and PyQt4.

import sys, time
from PyQt4.QtGui import QApplication
from PyQt4.QtCore import QThread, QTimer, QObject

class Worker(QObject):
    def run(self):
        time.sleep(1)

class ThreadController(QObject):
    def __init__(self, parent):
        QObject.__init__(self, parent)
        # No parent object provided; if so, we get the error
        # "QObject::moveToThread: Cannot move objects with a parent".
        # Who will deallocate this object, since it has no parent? I
        # assume the answer is "Python, maybe". Is that good enough?
        self.worker = Worker()
        self.workerThread = QThread(self)
        self.worker.moveToThread(self.workerThread)
        # Use method #2 below. Commnet out for a crash.
        parent.aboutToQuit.connect(self.del_)
        self.workerThread.start()

    # I'd like to run when when ~ThreadController is invoked. That's quite
    # differentfrom when __del__ is invoked. How?
    #
    # 1. Give up. Just invoke it manually. However, this is error-prone (i.e.
    #    I'll forget to do it at some point).
    # 2. Connect app.aboutToQuit to this. This seems fairly reasonable, but
    #    it would feel cleaner to invoke when the destructor is invoked,
    #    rather than earlier. Also, this means that the QApplication would
    #    need to be passed to every thread, which might involve awkwardness
    #    in passing it through several intervening subclasses.
    # 3. Connect destroyed(), which doesn't work -- this isn't emitted until
    #    the object is mostly dead, far after ~ThreadController was invoked,
    #    and won't be executed.
    # 4. Have __del__ invoke this, which doesn't work -- it only happens after
    #    ~ThreadController has finihed.
    def del_(self):
        print('del_')
        self.workerThread.quit()
        self.workerThread.wait()

    def __del__(self):
        print('__del__')
        # Crash when uncommented.
        #self.del_()

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

    # Exit the program shortly after the event loop starts up, but before the
    # thread finishes.
    QTimer.singleShot(200, app.exit)

    # Start a thread
    tm = ThreadController(app)

    # Run the main event loop.
    ret = app.exec_()
    print('done')
    sys.exit(ret)

​
-- 
Bryan A. Jones, Ph.D.
Associate Professor
Department of Electrical and Computer Engineering
231 Simrall / PO Box 9571
Mississippi State University
Mississippi state, MS 39762
http://www.ece.msstate.edu/~bjones
bjones AT ece DOT msstate DOT edu
voice 662-325-3149
fax 662-325-2298

Our Master, Jesus Christ, is on his way. He'll show up right on
time, his arrival guaranteed by the Blessed and Undisputed Ruler,
High King, High God.
- 1 Tim. 6:14b-15 (The Message)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.riverbankcomputing.com/pipermail/pyqt/attachments/20141103/d7fecd40/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: dest.py
Type: application/octet-stream
Size: 2335 bytes
Desc: not available
URL: <http://www.riverbankcomputing.com/pipermail/pyqt/attachments/20141103/d7fecd40/attachment.obj>


More information about the PyQt mailing list