Python PyQT4和线程:在QThread完成并更新ListWidget后关闭MainWidget

Python PyQT4和线程:在QThread完成并更新ListWidget后关闭MainWidget,python,multithreading,Python,Multithreading,我试图理解Python中线程是如何工作的。因此,我编写了一个应用程序,在一个单独的QThread中安装一些包 一旦worker完成(发出完成的信号),我想等待几秒钟,然后关闭MainWidget(见下文): def已完成(自): self.installbutton.setEnabled(True) self.listwidget.addItem(QtCore.QString(“流程完成,祝您愉快!”) 时间。睡眠(5) self.close() 现在的问题似乎是,在完成的回调中调用self.

我试图理解Python中线程是如何工作的。因此,我编写了一个应用程序,在一个单独的QThread中安装一些包

一旦worker完成(发出完成的信号),我想等待几秒钟,然后关闭MainWidget(见下文):

def已完成(自):
self.installbutton.setEnabled(True)
self.listwidget.addItem(QtCore.QString(“流程完成,祝您愉快!”)
时间。睡眠(5)
self.close()
现在的问题似乎是,在完成的回调中调用self.close会导致在窗口关闭之前不再更新ListWidget

我的猜测是,ListWidget和回调函数位于同一个堆栈中,因此ListWidget不再有机会终止。但如何解决这些问题呢

有什么建议可以克服这个问题吗

顺便说一句:我“被迫”使用Python2.7.5和PyQt4,以便与公司的其他部分兼容。。。这就是为什么我用老式的信号

代码如下:

导入系统 导入操作系统 导入时间 导入子流程 导入日志记录 log=logging.getLogger(_名称__) logging.basicConfig(级别=logging.DEBUG) 从PyQt4导入QtGui、QtCore def main(): app=QtGui.QApplication(sys.argv) w=InstallWizzard() w、 show() sys.exit(app.exec_()) 类InstallWizzard(QtGui.QMainWindow): def uuu init uuu(self,parent=None): QtGui.QMainWindow.\uuuuu init\uuuuu(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(“立即安装兄弟…”) hlayout.addWidget(self.installbutton) self.listwidget.addItem(QtCore.QString(r'单击“立即安装兄弟…”开始安装“)) self.centralwidget.setLayout(hlayout) self.connect(self.installbutton,QtCore.SIGNAL(“clicked()”),self.\u安装开始时) 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.\u cmd\u processed) hlayout.addWidget(self.listwidget) def_cmd_已处理(自身、mssg): self.listwidget.addItem(QtCore.QString(mssg)) def_on_安装_启动(自): self.installbutton.setEnabled(False) cmds=[(“安装comtypes”,r'easy_install comtypes')] self.thread.install(cmds) def完成(自我): self.installbutton.setEnabled(True) self.listwidget.addItem(QtCore.QString(“流程完成,祝您愉快!”) 时间。睡眠(5) self.close() 类工作程序(QtCore.QThread): def uuu init uuu(self,parent=None): QtCore.QThread.\uuuuu init\uuuuu(self,parent) 打印(“已启动的工作人员…”) def安装(自我,cmds): self.cmds=cmds self.start() def运行(自): 对于desc,self.cmds中的cmd: self.emit(QtCore.SIGNAL(“安装”)QtCore.QString(desc+“:…”) 尝试: self.\u write\u cmd\u行(cmd) mssg=“…成功” 例外情况除外,如e: mssg=QtCore.QString(str(“…Faillure:+e)) 自我发射(QtCore.SIGNAL(“install_mssg(QString)”),mssg) 打印(“来自工人的ond TSCHASS”) 定义(自我): self.quit() self.wait() 定义写入命令行(self,cmd): p=subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True) a、 b=p.沟通() 如果a中的“无法”或a中的“错误”或a中的“无法识别”: errormssg=“无法处理cmd!” 记录错误(ERRORMSG) 引发异常(错误MSSG) 其他: logging.debug(str(cmd)+“successful”) 如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu': main()
阅读您的问题和代码后。。在理解中,您有两个线程:主线程和工作线程,当您的工作线程完成时(我的意思是,这里的线程已到达代码的最后一行),您希望通知主线程关闭工作线程并切换到另一个窗口(可能)或执行其他操作

要做到这一点,显然需要与UI线程(主线程)通信,因此需要在工作者(线程)类中添加这几行代码

signal = QtCore.pyqtSignal(str) # Create a signal 
然后转到线程的最后一行,确保当工作人员到达该行时,工作将完成,并添加这一行以通知主线程

self.signal.emit('Some String here') # this will send the string over the signal to your UI thread 
现在跳转到InstallWizzard类**并添加以下行 在\uuuu init\uuuuu方法中,在**self.thread=Worker()下面添加这一行。

现在,在您完成的方法中,您可以终止/关闭/退出您正在使用的方法

self.thread.quit() # as you might guessed this will quit your thread.
如果要强制关闭工作进程,也可以将quit()替换为terminate(),但请阅读QThread::terminate:

警告:此功能很危险,不鼓励使用。这个 线程可以在其代码路径中的任意点终止。线程可以是 在修改数据时终止。这根线没有机会断开 清理后,自己,解锁任何持有的互斥等简而言之,使用 此功能仅在绝对必要时使用

如果您关心将通过Worker的信号发送的字符串,请向您完成的方法添加新参数以访问该字符串。 就是这样:)

我知道我现在回答你的问题已经太晚了(1年前),但这可能对其他开发人员有所帮助……无论如何,如果你是
self.thread.quit() # as you might guessed this will quit your thread.