我写了一个简单的程序,它有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的新手,我第一次使用线程。
答案 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
模式之一,并通过Signals
和Slots
与主GUI线程进行通信。
另外,在下面的代码中,
app = QtGui.QApplication(sys.argv)
ex = Class()
sys.exit(app.exec_())
ex.update()
app.exec_
启动事件循环并将阻塞直到Qt退出。 Python不会运行ex.update()
命令,直到Qt退出并且ex
窗口已被删除,因此您应该删除该命令。