I'm trying to understand how threading works in Python. Therefore I wrote an application that is installing some packages in a separate QThread.
Once the worker is finished (finished Signal emitted), I'd like to wait a few seconds and then Close the MainWidget (see below):
def finished(self):
self.installbutton.setEnabled(True)
self.listwidget.addItem(QtCore.QString("Process complete, have a nice day!"))
time.sleep(5)
self.close()
The Problem seems now, that calling self.close within the finished-callback leads to a Situation where the ListWidget is no more updated anymore before the window closes.
My guess is, that the ListWidget and the callback function live in the same stack and therefore the ListWidget has no Chance to terminate any more. But how to solve these kind of issues?
Any suggestions how I can overcome this?
By the way: I'm "forced" to use Python 2.7.5 and PyQt4 in order to be compliant with the rest of my Company... that's why I'm using the old-style signals
Here the code:
import sys
import os
import time
import subprocess
import logging
log = logging.getLogger(__name__)
logging.basicConfig(level=logging.DEBUG)
from PyQt4 import QtGui, QtCore
def main():
app = QtGui.QApplication(sys.argv)
w = InstallWizzard()
w.show()
sys.exit(app.exec_())
class InstallWizzard(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self,parent)
self.centralwidget = QtGui.QWidget(self)
self.setCentralWidget(self.centralwidget)
self.thread = Worker()
hlayout = QtGui.QVBoxLayout()
self.listwidget = QtGui.QListWidget()
self.installbutton = QtGui.QPushButton()
self.installbutton.setText("Install Brother now...")
hlayout.addWidget(self.installbutton)
self.listwidget.addItem(QtCore.QString(r'Click "Install Brother now... to start installation"'))
self.centralwidget.setLayout(hlayout)
self.connect(self.installbutton, QtCore.SIGNAL("clicked()"),self._on_installation_start)
self.connect(self.thread, QtCore.SIGNAL("finished()"), self.finished)
# self.connect(self.thread, QtCore.SIGNAL("terminated()"), self.updateUI)
self.connect(self.thread, QtCore.SIGNAL("install_mssg(QString)"), self._cmd_processed)
hlayout.addWidget(self.listwidget)
def _cmd_processed(self, mssg):
self.listwidget.addItem(QtCore.QString(mssg))
def _on_installation_start(self):
self.installbutton.setEnabled(False)
cmds = [("Installing comtypes", r'easy_install comtypes')]
self.thread.install(cmds)
def finished(self):
self.installbutton.setEnabled(True)
self.listwidget.addItem(QtCore.QString("Process complete, have a nice day!"))
time.sleep(5)
self.close()
class Worker(QtCore.QThread):
def __init__(self, parent = None):
QtCore.QThread.__init__(self,parent)
print("Started Worker...")
def install(self, cmds):
self.cmds = cmds
self.start()
def run(self):
for desc, cmd in self.cmds:
self.emit(QtCore.SIGNAL("install_mssg(QString)"),QtCore.QString(desc + ": ..."))
try:
self._write_cmd_line(cmd)
mssg = "... Successful"
except Exception as e:
mssg = QtCore.QString(str("... Faillure: " + e))
self.emit(QtCore.SIGNAL("install_mssg(QString)"),mssg)
print("ond tschuss from worker")
def __del__(self):
self.quit()
self.wait()
def _write_cmd_line(self, cmd):
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
a,b = p.communicate()
if "cannot" in a or "error" in a or "not recognized" in a:
errormssg = "Could not proccess cmd!"
logging.error(errormssg)
raise Exception(errormssg)
else:
logging.debug(str(cmd) + " successful")
if __name__ == '__main__':
main()