<div dir="ltr"><div class="markdown-here-wrapper" style><p style="margin:1.2em 0px!important">All,</p>
<p style="margin:1.2em 0px!important">Pardon the double post. I saw a few obvious bugs after hitting send. My apologies. Here is the improved version.</p>
<p style="margin:1.2em 0px!important">Bryan</p>
<pre style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;font-size:1em;line-height:1.2em;margin:1.2em 0px"><code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;display:inline;background-color:rgb(248,248,248);white-space:pre;overflow:auto;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;border:1px solid rgb(204,204,204);padding:0.5em 0.7em;display:block!important"># Test program to ask about destructors and PyQt4.
import sys, time
from PyQt4.QtGui import QApplication
from PyQt4.QtCore import QThread, QTimer, QObject, pyqtSignal
class Worker(QObject):
def onStartWork(self):
time.sleep(1)
class ThreadController(QObject):
startWork = pyqtSignal()
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".
# Likewise, calling setParent after moving the object produces
# "QObject::setParent: Cannot set parent, new parent is in a different
# thread". 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 an ominous warning which will
# crash in a more complex program: "QThread: Destroyed while thread is
# still running".
#parent.aboutToQuit.connect(self.del_)
self.startWork.connect(self.worker.onStartWork)
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)
</code></pre><div title="MDH:QWxsLDxkaXY+PGJyPjwvZGl2PjxkaXY+UGFyZG9uIHRoZSBkb3VibGUgcG9zdC4gSSBzYXcgYSBm
ZXcgb2J2aW91cyBidWdzIGFmdGVyIGhpdHRpbmcgc2VuZC4gTXkgYXBvbG9naWVzLiBIZXJlIGlz
IHRoZSBpbXByb3ZlZCB2ZXJzaW9uLjwvZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+QnJ5YW48L2Rp
dj48ZGl2Pjxicj48L2Rpdj48ZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAjIFRlc3QgcHJvZ3JhbSB0
byBhc2sgYWJvdXQgZGVzdHJ1Y3RvcnMgYW5kIFB5UXQ0LjwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNw
OyZuYnNwOzwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyBpbXBvcnQgc3lzLCB0aW1lPC9kaXY+PGRp
dj4mbmJzcDsgJm5ic3A7IGZyb20gUHlRdDQuUXRHdWkgaW1wb3J0IFFBcHBsaWNhdGlvbjwvZGl2
PjxkaXY+Jm5ic3A7ICZuYnNwOyBmcm9tIFB5UXQ0LlF0Q29yZSBpbXBvcnQgUVRocmVhZCwgUVRp
bWVyLCBRT2JqZWN0LCBweXF0U2lnbmFsPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7Jm5ic3A7PC9k
aXY+PGRpdj4mbmJzcDsgJm5ic3A7IGNsYXNzIFdvcmtlcihRT2JqZWN0KTo8L2Rpdj48ZGl2PiZu
YnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBkZWYgb25TdGFydFdvcmsoc2VsZik6PC9kaXY+PGRp
dj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyB0aW1lLnNsZWVwKDEp
PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7Jm5ic3A7PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7IGNs
YXNzIFRocmVhZENvbnRyb2xsZXIoUU9iamVjdCk6PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZu
YnNwOyAmbmJzcDsgc3RhcnRXb3JrID0gcHlxdFNpZ25hbCgpPC9kaXY+PGRpdj4mbmJzcDsgJm5i
c3A7ICZuYnNwOyAmbmJzcDsgZGVmIF9faW5pdF9fKHNlbGYsIHBhcmVudCk6PC9kaXY+PGRpdj4m
bmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBRT2JqZWN0Ll9faW5pdF9f
KHNlbGYsIHBhcmVudCk8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJz
cDsgJm5ic3A7ICMgTm8gcGFyZW50IG9iamVjdCBwcm92aWRlZDsgaWYgc28sIHdlIGdldCB0aGUg
ZXJyb3I8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7
ICMgIlFPYmplY3Q6Om1vdmVUb1RocmVhZDogQ2Fubm90IG1vdmUgb2JqZWN0cyB3aXRoIGEgcGFy
ZW50Ii48L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7
ICMgTGlrZXdpc2UsIGNhbGxpbmcgc2V0UGFyZW50IGFmdGVyIG1vdmluZyB0aGUgb2JqZWN0IHBy
b2R1Y2VzPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNw
OyAjICJRT2JqZWN0OjpzZXRQYXJlbnQ6IENhbm5vdCBzZXQgcGFyZW50LCBuZXcgcGFyZW50IGlz
IGluIGEgZGlmZmVyZW50PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5i
c3A7ICZuYnNwOyAjIHRocmVhZCIuIFdobyB3aWxsIGRlYWxsb2NhdGUgdGhpcyBvYmplY3QsIHNp
bmNlIGl0IGhhcyBubyBwYXJlbnQ/IEk8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZu
YnNwOyAmbmJzcDsgJm5ic3A7ICMgYXNzdW1lIHRoZSBhbnN3ZXIgaXMgIlB5dGhvbiwgbWF5YmUi
LiBJcyB0aGF0IGdvb2QgZW5vdWdoPzwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5i
c3A7ICZuYnNwOyAmbmJzcDsgc2VsZi53b3JrZXIgPSBXb3JrZXIoKTwvZGl2PjxkaXY+Jm5ic3A7
ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgc2VsZi53b3JrZXJUaHJlYWQgPSBR
VGhyZWFkKHNlbGYpPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7
ICZuYnNwOyBzZWxmLndvcmtlci5tb3ZlVG9UaHJlYWQoc2VsZi53b3JrZXJUaHJlYWQpPC9kaXY+
PGRpdj4mbmJzcDsgJm5ic3A7Jm5ic3A7PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAm
bmJzcDsgJm5ic3A7ICZuYnNwOyAjIFVzZSBtZXRob2QgIzIgYmVsb3cuIENvbW1uZXQgb3V0IGZv
ciBhbiBvbWlub3VzIHdhcm5pbmcgd2hpY2ggd2lsbDwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAm
bmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyBjcmFzaCBpbiBhIG1vcmUgY29tcGxleCBwcm9n
cmFtOiAiUVRocmVhZDogRGVzdHJveWVkIHdoaWxlIHRocmVhZCBpczwvZGl2PjxkaXY+Jm5ic3A7
ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyBzdGlsbCBydW5uaW5nIi48L2Rp
dj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICNwYXJlbnQu
YWJvdXRUb1F1aXQuY29ubmVjdChzZWxmLmRlbF8pPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZu
YnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBzZWxmLnN0YXJ0V29yay5jb25uZWN0KHNlbGYud29y
a2VyLm9uU3RhcnRXb3JrKTwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZu
YnNwOyAmbmJzcDsgc2VsZi53b3JrZXJUaHJlYWQuc3RhcnQoKTwvZGl2PjxkaXY+Jm5ic3A7ICZu
YnNwOyZuYnNwOzwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgSSdkIGxp
a2UgdG8gcnVuIHdoZW4gd2hlbiB+VGhyZWFkQ29udHJvbGxlciBpcyBpbnZva2VkLiBUaGF0J3Mg
cXVpdGU8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjIGRpZmZlcmVudGZy
b20gd2hlbiBfX2RlbF9fIGlzIGludm9rZWQuIEhvdz88L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsg
Jm5ic3A7ICZuYnNwOyAjPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyAx
LiBHaXZlIHVwLiBKdXN0IGludm9rZSBpdCBtYW51YWxseS4gSG93ZXZlciwgdGhpcyBpcyBlcnJv
ci1wcm9uZSAoaS5lLjwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgJm5i
c3A7ICZuYnNwO0knbGwgZm9yZ2V0IHRvIGRvIGl0IGF0IHNvbWUgcG9pbnQpLjwvZGl2PjxkaXY+
Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgMi4gQ29ubmVjdCBhcHAuYWJvdXRUb1F1aXQg
dG8gdGhpcy4gVGhpcyBzZWVtcyBmYWlybHkgcmVhc29uYWJsZSwgYnV0PC9kaXY+PGRpdj4mbmJz
cDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyAmbmJzcDsgJm5ic3A7aXQgd291bGQgZmVlbCBjbGVh
bmVyIHRvIGludm9rZSB3aGVuIHRoZSBkZXN0cnVjdG9yIGlzIGludm9rZWQsPC9kaXY+PGRpdj4m
bmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyAmbmJzcDsgJm5ic3A7cmF0aGVyIHRoYW4gZWFy
bGllci4gQWxzbywgdGhpcyBtZWFucyB0aGF0IHRoZSBRQXBwbGljYXRpb24gd291bGQ8L2Rpdj48
ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjICZuYnNwOyAmbmJzcDtuZWVkIHRvIGJl
IHBhc3NlZCB0byBldmVyeSB0aHJlYWQsIHdoaWNoIG1pZ2h0IGludm9sdmUgYXdrd2FyZG5lc3M8
L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjICZuYnNwOyAmbmJzcDtpbiBw
YXNzaW5nIGl0IHRocm91Z2ggc2V2ZXJhbCBpbnRlcnZlbmluZyBzdWJjbGFzc2VzLjwvZGl2Pjxk
aXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgMy4gQ29ubmVjdCBkZXN0cm95ZWQoKSwg
d2hpY2ggZG9lc24ndCB3b3JrIC0tIHRoaXMgaXNuJ3QgZW1pdHRlZCB1bnRpbDwvZGl2PjxkaXY+
Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgJm5ic3A7ICZuYnNwO3RoZSBvYmplY3QgaXMg
bW9zdGx5IGRlYWQsIGZhciBhZnRlciB+VGhyZWFkQ29udHJvbGxlciB3YXMgaW52b2tlZCw8L2Rp
dj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjICZuYnNwOyAmbmJzcDthbmQgd29u
J3QgYmUgZXhlY3V0ZWQuPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyA0
LiBIYXZlIF9fZGVsX18gaW52b2tlIHRoaXMsIHdoaWNoIGRvZXNuJ3Qgd29yayAtLSBpdCBvbmx5
IGhhcHBlbnMgYWZ0ZXI8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjICZu
YnNwOyAmbmJzcDt+VGhyZWFkQ29udHJvbGxlciBoYXMgZmluaWhlZC48L2Rpdj48ZGl2PiZuYnNw
OyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBkZWYgZGVsXyhzZWxmKTo8L2Rpdj48ZGl2PiZuYnNwOyAm
bmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7IHByaW50KCdkZWxfJyk8L2Rpdj48ZGl2
PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7IHNlbGYud29ya2VyVGhy
ZWFkLnF1aXQoKTwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAm
bmJzcDsgc2VsZi53b3JrZXJUaHJlYWQud2FpdCgpPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7Jm5i
c3A7PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgZGVmIF9fZGVsX18oc2Vs
Zik6PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBw
cmludCgnX19kZWxfXycpPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5i
c3A7ICZuYnNwOyAjIENyYXNoIHdoZW4gdW5jb21tZW50ZWQuPC9kaXY+PGRpdj4mbmJzcDsgJm5i
c3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjc2VsZi5kZWxfKCk8L2Rpdj48ZGl2PiZu
YnNwOyAmbmJzcDsmbmJzcDs8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgaWYgX19uYW1lX18gPT0g
J19fbWFpbl9fJzo8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBhcHAgPSBR
QXBwbGljYXRpb24oc3lzLmFyZ3YpPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7Jm5ic3A7PC9kaXY+
PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyBFeGl0IHRoZSBwcm9ncmFtIHNob3J0
bHkgYWZ0ZXIgdGhlIGV2ZW50IGxvb3Agc3RhcnRzIHVwLCBidXQgYmVmb3JlIHRoZTwvZGl2Pjxk
aXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgdGhyZWFkIGZpbmlzaGVzLjwvZGl2Pjxk
aXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7IFFUaW1lci5zaW5nbGVTaG90KDIwMCwgYXBw
LmV4aXQpPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7Jm5ic3A7PC9kaXY+PGRpdj4mbmJzcDsgJm5i
c3A7ICZuYnNwOyAmbmJzcDsgIyBTdGFydCBhIHRocmVhZDwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNw
OyAmbmJzcDsgJm5ic3A7IHRtID0gVGhyZWFkQ29udHJvbGxlcihhcHApPC9kaXY+PGRpdj4mbmJz
cDsgJm5ic3A7Jm5ic3A7PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyBS
dW4gdGhlIG1haW4gZXZlbnQgbG9vcC48L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZu
YnNwOyByZXQgPSBhcHAuZXhlY18oKTwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5i
c3A7IHByaW50KCdkb25lJyk8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBz
eXMuZXhpdChyZXQpPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7Jm5ic3A7PC9kaXY+PC9kaXY+" style="height:0;font-size:0em;padding:0;margin:0"></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Nov 3, 2014 at 3:59 PM, Bryan A. Jones <span dir="ltr"><<a href="mailto:bjones@ece.msstate.edu" target="_blank">bjones@ece.msstate.edu</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><p style="margin:1.2em 0px!important">All,</p>
<p style="margin:1.2em 0px!important">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.</p>
<p style="margin:1.2em 0px!important">Bryan</p>
<pre style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;font-size:1em;line-height:1.2em;margin:1.2em 0px"><code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;display:inline;background-color:rgb(248,248,248);white-space:pre-wrap;overflow:auto;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;border:1px solid rgb(204,204,204);padding:0.5em 0.7em;display:block!important"># 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)
</code></pre><div title="MDH:QWxsLDxkaXY+PGJyPjwvZGl2PjxkaXY+SSdtIGNvbmZ1c2VkIHdoZW4gaXQgY29tZXMgdG8gdGhl
IHByb3BlciB3YXkgdG8gbWVzaCBRdCdzIG1vZGVsIG9mIGNyZWF0aW5nIGEgdHJlZSBvZiBwYXJl
bnRlZCBvYmplY3RzIHdoaWNoIGRlc3Ryb3kgdGhlbXNlbHZlcyB3aGVuIG5vIGxvbmdlciB1c2Vk
IHdpdGggUHl0aG9uJ3MgImRlbGV0ZSBpdCB3aGVuIEkgZmVlbCBsaWtlIGl0IiBnYXJiYWdlIGNv
bGxlY3Rvci4gSW4gcGFydGljdWxhciwgSSdkIGxpa2UgdG8gc2h1dCBkb3duIHRocmVhZHMgd2hl
biB0aGUgdW5kZXJseWluZyBRdCBvYmplY3RzIGFyZSBkZXN0cm95ZWQsIGJ1dCBJIGNhbid0IGZp
Z3VyZSBvdXQgaG93IHRvIGRvIHRoYXQuIEFueSBhZHZpY2UgYW5kIHdpc2RvbSB3b3VsZCBiZSBh
cHByZWNpYXRlZC48L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2PkJyeWFuPC9kaXY+PGRpdj48YnI+
PC9kaXY+PGRpdj48ZGl2PiZuYnNwOyAmbmJzcDsgIyBUZXN0IHByb2dyYW0gdG8gYXNrIGFib3V0
IGRlc3RydWN0b3JzIGFuZCBQeVF0NC48L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsmbmJzcDs8L2Rp
dj48ZGl2PiZuYnNwOyAmbmJzcDsgaW1wb3J0IHN5cywgdGltZTwvZGl2PjxkaXY+Jm5ic3A7ICZu
YnNwOyBmcm9tIFB5UXQ0LlF0R3VpIGltcG9ydCBRQXBwbGljYXRpb248L2Rpdj48ZGl2PiZuYnNw
OyAmbmJzcDsgZnJvbSBQeVF0NC5RdENvcmUgaW1wb3J0IFFUaHJlYWQsIFFUaW1lciwgUU9iamVj
dDwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyZuYnNwOzwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyBj
bGFzcyBXb3JrZXIoUU9iamVjdCk6PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJz
cDsgZGVmIHJ1bihzZWxmKTo8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAm
bmJzcDsgJm5ic3A7IHRpbWUuc2xlZXAoMSk8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsmbmJzcDs8
L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgY2xhc3MgVGhyZWFkQ29udHJvbGxlcihRT2JqZWN0KTo8
L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBkZWYgX19pbml0X18oc2VsZiwg
cGFyZW50KTo8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5i
c3A7IFFPYmplY3QuX19pbml0X18oc2VsZiwgcGFyZW50KTwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNw
OyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyBObyBwYXJlbnQgb2JqZWN0IHByb3ZpZGVk
OyBpZiBzbywgd2UgZ2V0IHRoZSBlcnJvcjwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsg
Jm5ic3A7ICZuYnNwOyAmbmJzcDsgIyAiUU9iamVjdDo6bW92ZVRvVGhyZWFkOiBDYW5ub3QgbW92
ZSBvYmplY3RzIHdpdGggYSBwYXJlbnQiLjwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsg
Jm5ic3A7ICZuYnNwOyAmbmJzcDsgIyBXaG8gd2lsbCBkZWFsbG9jYXRlIHRoaXMgb2JqZWN0LCBz
aW5jZSBpdCBoYXMgbm8gcGFyZW50PyBJPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAm
bmJzcDsgJm5ic3A7ICZuYnNwOyAjIGFzc3VtZSB0aGUgYW5zd2VyIGlzICJQeXRob24sIG1heWJl
Ii4gSXMgdGhhdCBnb29kIGVub3VnaD88L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZu
YnNwOyAmbmJzcDsgJm5ic3A7IHNlbGYud29ya2VyID0gV29ya2VyKCk8L2Rpdj48ZGl2PiZuYnNw
OyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7IHNlbGYud29ya2VyVGhyZWFkID0g
UVRocmVhZChzZWxmKTwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNw
OyAmbmJzcDsgc2VsZi53b3JrZXIubW92ZVRvVGhyZWFkKHNlbGYud29ya2VyVGhyZWFkKTwvZGl2
PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyBVc2UgbWV0
aG9kICMyIGJlbG93LiBDb21tbmV0IG91dCBmb3IgYSBjcmFzaC48L2Rpdj48ZGl2PiZuYnNwOyAm
bmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7IHBhcmVudC5hYm91dFRvUXVpdC5jb25u
ZWN0KHNlbGYuZGVsXyk8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJz
cDsgJm5ic3A7IHNlbGYud29ya2VyVGhyZWFkLnN0YXJ0KCk8L2Rpdj48ZGl2PiZuYnNwOyAmbmJz
cDsmbmJzcDs8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjIEknZCBsaWtl
IHRvIHJ1biB3aGVuIHdoZW4gflRocmVhZENvbnRyb2xsZXIgaXMgaW52b2tlZC4gVGhhdCdzIHF1
aXRlPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyBkaWZmZXJlbnRmcm9t
IHdoZW4gX19kZWxfXyBpcyBpbnZva2VkLiBIb3c/PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZu
YnNwOyAmbmJzcDsgIzwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgMS4g
R2l2ZSB1cC4gSnVzdCBpbnZva2UgaXQgbWFudWFsbHkuIEhvd2V2ZXIsIHRoaXMgaXMgZXJyb3It
cHJvbmUgKGkuZS48L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjICZuYnNw
OyAmbmJzcDtJJ2xsIGZvcmdldCB0byBkbyBpdCBhdCBzb21lIHBvaW50KS48L2Rpdj48ZGl2PiZu
YnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjIDIuIENvbm5lY3QgYXBwLmFib3V0VG9RdWl0IHRv
IHRoaXMuIFRoaXMgc2VlbXMgZmFpcmx5IHJlYXNvbmFibGUsIGJ1dDwvZGl2PjxkaXY+Jm5ic3A7
ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgJm5ic3A7ICZuYnNwO2l0IHdvdWxkIGZlZWwgY2xlYW5l
ciB0byBpbnZva2Ugd2hlbiB0aGUgZGVzdHJ1Y3RvciBpcyBpbnZva2VkLDwvZGl2PjxkaXY+Jm5i
c3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgJm5ic3A7ICZuYnNwO3JhdGhlciB0aGFuIGVhcmxp
ZXIuIEFsc28sIHRoaXMgbWVhbnMgdGhhdCB0aGUgUUFwcGxpY2F0aW9uIHdvdWxkPC9kaXY+PGRp
dj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyAmbmJzcDsgJm5ic3A7bmVlZCB0byBiZSBw
YXNzZWQgdG8gZXZlcnkgdGhyZWFkLCB3aGljaCBtaWdodCBpbnZvbHZlIGF3a3dhcmRuZXNzPC9k
aXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyAmbmJzcDsgJm5ic3A7aW4gcGFz
c2luZyBpdCB0aHJvdWdoIHNldmVyYWwgaW50ZXJ2ZW5pbmcgc3ViY2xhc3Nlcy48L2Rpdj48ZGl2
PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjIDMuIENvbm5lY3QgZGVzdHJveWVkKCksIHdo
aWNoIGRvZXNuJ3Qgd29yayAtLSB0aGlzIGlzbid0IGVtaXR0ZWQgdW50aWw8L2Rpdj48ZGl2PiZu
YnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjICZuYnNwOyAmbmJzcDt0aGUgb2JqZWN0IGlzIG1v
c3RseSBkZWFkLCBmYXIgYWZ0ZXIgflRocmVhZENvbnRyb2xsZXIgd2FzIGludm9rZWQsPC9kaXY+
PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyAmbmJzcDsgJm5ic3A7YW5kIHdvbid0
IGJlIGV4ZWN1dGVkLjwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgNC4g
SGF2ZSBfX2RlbF9fIGludm9rZSB0aGlzLCB3aGljaCBkb2Vzbid0IHdvcmsgLS0gaXQgb25seSBo
YXBwZW5zIGFmdGVyPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyAmbmJz
cDsgJm5ic3A7flRocmVhZENvbnRyb2xsZXIgaGFzIGZpbmloZWQuPC9kaXY+PGRpdj4mbmJzcDsg
Jm5ic3A7ICZuYnNwOyAmbmJzcDsgZGVmIGRlbF8oc2VsZik6PC9kaXY+PGRpdj4mbmJzcDsgJm5i
c3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBwcmludCgnZGVsXycpPC9kaXY+PGRpdj4m
bmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBzZWxmLndvcmtlclRocmVh
ZC5xdWl0KCk8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5i
c3A7IHNlbGYud29ya2VyVGhyZWFkLndhaXQoKTwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyZuYnNw
OzwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7IGRlZiBfX2RlbF9fKHNlbGYp
OjwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgcHJp
bnQoJ19fZGVsX18nKTwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNw
OyAmbmJzcDsgIyBDcmFzaCB3aGVuIHVuY29tbWVudGVkLjwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNw
OyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgI3NlbGYuZGVsXygpPC9kaXY+PGRpdj4mbmJz
cDsgJm5ic3A7Jm5ic3A7PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7IGlmIF9fbmFtZV9fID09ICdf
X21haW5fXyc6PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgYXBwID0gUUFw
cGxpY2F0aW9uKHN5cy5hcmd2KTwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyZuYnNwOzwvZGl2Pjxk
aXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgRXhpdCB0aGUgcHJvZ3JhbSBzaG9ydGx5
IGFmdGVyIHRoZSBldmVudCBsb29wIHN0YXJ0cyB1cCwgYnV0IGJlZm9yZSB0aGU8L2Rpdj48ZGl2
PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjIHRocmVhZCBmaW5pc2hlcy48L2Rpdj48ZGl2
PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBRVGltZXIuc2luZ2xlU2hvdCgyMDAsIGFwcC5l
eGl0KTwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyZuYnNwOzwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNw
OyAmbmJzcDsgJm5ic3A7ICMgU3RhcnQgYSB0aHJlYWQ8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsg
Jm5ic3A7ICZuYnNwOyB0bSA9IFRocmVhZENvbnRyb2xsZXIoYXBwKTwvZGl2PjxkaXY+Jm5ic3A7
ICZuYnNwOyZuYnNwOzwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgUnVu
IHRoZSBtYWluIGV2ZW50IGxvb3AuPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJz
cDsgcmV0ID0gYXBwLmV4ZWNfKCk8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNw
OyBwcmludCgnZG9uZScpPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgc3lz
LmV4aXQocmV0KTwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyZuYnNwOzwvZGl2PjxkaXY+PGJyPjwv
ZGl2PjwvZGl2Pg==" style="min-height:0;font-size:0em;padding:0;margin:0"></div></div><div>-- <br>Bryan A. Jones, Ph.D.<br>Associate Professor<br>Department of Electrical and Computer Engineering<br>231 Simrall / PO Box 9571<br>Mississippi State University<br>Mississippi state, MS 39762<br><a href="http://www.ece.msstate.edu/~bjones" target="_blank">http://www.ece.msstate.edu/~bjones</a><br>bjones AT ece DOT msstate DOT edu<br>voice <a href="tel:662-325-3149" value="+16623253149" target="_blank">662-325-3149</a><br>fax <a href="tel:662-325-2298" value="+16623252298" target="_blank">662-325-2298</a><br><br>Our Master, Jesus Christ, is on his way. He'll show up right on<br>time, his arrival guaranteed by the Blessed and Undisputed Ruler,<br>High King, High God.<br>- 1 Tim. 6:14b-15 (The Message)<br>
</div></div>
</blockquote></div><br><br clear="all"><div><br></div>-- <br>Bryan A. Jones, Ph.D.<br>Associate Professor<br>Department of Electrical and Computer Engineering<br>231 Simrall / PO Box 9571<br>Mississippi State University<br>Mississippi state, MS 39762<br><a href="http://www.ece.msstate.edu/~bjones" target="_blank">http://www.ece.msstate.edu/~bjones</a><br>bjones AT ece DOT msstate DOT edu<br>voice 662-325-3149<br>fax 662-325-2298<br><br>Our Master, Jesus Christ, is on his way. He'll show up right on<br>time, his arrival guaranteed by the Blessed and Undisputed Ruler,<br>High King, High God.<br>- 1 Tim. 6:14b-15 (The Message)<br>
</div>