pyQt和线程应用程序崩溃

时间:2016-03-15 23:06:05

标签: multithreading python-2.7 pyqt

我写了一个简单的程序,它有2个按钮(启动和取消)的pyQt接口。开始按钮在后台运行一些计算(通过启动更新功能),由于线程,我仍然可以使用UI。 但应用程序在10秒 - 2分钟后崩溃。 UI只是消失,程序关闭。

当我使用pythonw在没有控制台线程崩溃的情况下运行应用程序约25秒后但gui仍然有效。

#!/usr/bin/python
import threading
import sys
from PyQt4 import QtGui, QtCore
import time
import os


class Class(QtGui.QWidget):

    def __init__(self):
        #Some init variables
        self.initUI()

    def initUI(self):
        #some UI
        self.show()

    def update(self,stop_event):
            while True and not stop_event.isSet():
                self.updateSpeed()
                self.updateDistance()
                self.printLogs()
                self.saveCSV()
                self.guiUpdate()
                time.sleep(1)

    #gui button function
    def initiate(self):
        self.stop_event = threading.Event()
        self.c_thread = threading.Thread(target = self.update, args=(self.stop_event,))
        self.c_thread.start()

    #Also gui button function
    def cancelTracking(self):
        self.stop_event.set()
        self.close()

def main():

    app = QtGui.QApplication(sys.argv)
    ex = Class()
    sys.exit(app.exec_())
    ex.update()

if __name__ == '__main__':
    main()

我不知道我是否正在做正确的线程。我在堆栈上找到了这样的例子。我是python的新手,我第一次使用线程。

2 个答案:

答案 0 :(得分:2)

这很可能是因为在单独的线程中调用了GUI函数。不允许来自setText()的{​​{1}}之类的PyQt GUI调用。在主线程之外有任何PyQt绘画的东西都行不通。解决此问题的一种方法是让您的线程发出信号,以便在数据准备就绪时更新GUI。另一种方法是让计时器定期检查新数据并在一定时间后更新QLineEdit

paintEvent

另一件可能发生的事情是两个线程试图访问同一个变量的死锁。我已经读过这在python中不可能实现,但是我从PySide和其他Python C扩展库的组合中体验过它。

也可能希望在关闭时加入线程,或者在程序关闭之前使用#!/usr/bin/python import threading import sys from PyQt4 import QtGui, QtCore import time import os class Class(QtGui.QWidget): display_update = QtCore.pyqtSignal() # ADDED def __init__(self): #Some init variables self.initUI() def initUI(self): #some UI self.display_update.connect(self.guiUpdate) # ADDED self.show() def update(self): while True and not self.stop_event.isSet(): self.updateSpeed() self.updateDistance() self.printLogs() self.saveCSV() # self.guiUpdate() self.display_update.emit() # ADDED time.sleep(1) #gui button function def initiate(self): self.stop_event = threading.Event() self.c_thread = threading.Thread(target = self.update) self.c_thread.start() #Also gui button function def cancelTracking(self): self.stop_event.set() self.close() def main(): app = QtGui.QApplication(sys.argv) ex = Class() sys.exit(app.exec_()) # ex.update() # - this does nothing if __name__ == '__main__': main() 信号加入线程。

答案 1 :(得分:1)

Qt documentation for QThreads提供了两种使用线程的流行模式。您可以将QThread(旧方法)子类化,也可以使用工作模型,在其中使用工作函数创建自定义QObject并在单独运行它们QThread

在任何一种情况下,您都无法直接从后台线程更新GUI,因此在update函数中,guiUpdate调用很可能会在Qt尝试更改任何内容时崩溃GUI元素。

运行后台进程的正确方法是使用两种QThread模式之一,并通过SignalsSlots与主GUI线程进行通信。

另外,在下面的代码中,

app = QtGui.QApplication(sys.argv)
ex = Class()
sys.exit(app.exec_())
ex.update()

app.exec_启动事件循环并将阻塞直到Qt退出。 Python不会运行ex.update()命令,直到Qt退出并且ex窗口已被删除,因此您应该删除该命令。