我的程序中存在一些线程问题。我有一个主程序和一个 GUI 类,是用 PyQt 创建的。我创建了一个关于我的问题的小例子。 当我启动 python 脚本并按开始时,进度条工作正常,但我收到以下警告:
QBackingStore::endPaint() called with active painter on backingstore paint device
QObject::setParent: Cannot set parent, new parent is in a different thread
这些警报是由于不同的线程而发生的。但说实话,我不知道如何处理对象,比如 gui 类的进度条。 我尝试了很多方法,但还没有找到好的解决方案。 按开始,进度条开始,按停止,进度条停止。但这是下一个问题,当我按下停止键时,大多数情况下我的内核都会死掉。我猜这与线程的问题有关?!
使用线程的原因是为了让脚本在运行时仍然可以与之交互。
附件是我的两个 python 文件:我的程序和 gui。
主程序:
#MAINPROGRAM
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication
import sys
import GUI
import threading
import time
class exampleprogram(QtWidgets.QMainWindow, GUI.Ui_MainWindow):
def __init__(self, parent=None):
super(exampleprogram, self).__init__(parent)
self.setupUi(self)
self.pushButton_Start.clicked.connect(self.start)
self.pushButton_Stop.clicked.connect(self.stop)
self.running = False
def start(self):
if(self.running == False):
print("Start")
self.thread = threading.Thread(target=self.run, args=())
self.thread.start()
def stop(self):
print("Stop")
self.running = False
def run(self):
self.running = True
x = 0
thread = threading.currentThread()
while getattr(thread, "do_run", True):
self.thread.do_run = self.running
if(x == 100):
thread.do_run = False
self.progressBar.setValue(x)
time.sleep(0.1)
x = x+1
self.stop()
def main():
app = QApplication(sys.argv)
form = exampleprogram()
form.show()
app.exec_()
if __name__ == '__main__':
main()
图形用户界面:
#GUI
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(573, 92)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.layoutWidget = QtWidgets.QWidget(self.centralwidget)
self.layoutWidget.setGeometry(QtCore.QRect(20, 20, 195, 30))
self.layoutWidget.setObjectName("layoutWidget")
self.formLayout_3 = QtWidgets.QFormLayout(self.layoutWidget)
self.formLayout_3.setContentsMargins(0, 0, 0, 0)
self.formLayout_3.setObjectName("formLayout_3")
self.pushButton_Start = QtWidgets.QPushButton(self.layoutWidget)
self.pushButton_Start.setObjectName("pushButton_Start")
self.formLayout_3.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.pushButton_Start)
self.pushButton_Stop = QtWidgets.QPushButton(self.layoutWidget)
self.pushButton_Stop.setObjectName("pushButton_Stop")
self.formLayout_3.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.pushButton_Stop)
self.progressBar = QtWidgets.QProgressBar(self.centralwidget)
self.progressBar.setGeometry(QtCore.QRect(230, 20, 311, 23))
self.progressBar.setProperty("value", 0)
self.progressBar.setObjectName("progressBar")
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "Test Gui"))
self.pushButton_Start.setText(_translate("MainWindow", "Start"))
self.pushButton_Stop.setText(_translate("MainWindow", "Stop"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
有人有想法,如何解决它吗?
编辑:停止运行功能后,应该可以通过按开始按钮再次运行它。因此,无论是通过计数器 x 停止还是通过按停止按钮停止都没有关系。重要的是不要多次启动该函数。
非常感谢!
安德鲁
最佳答案
虽然可以将 Python 线程与 PyQt 一起使用,但通常最好使用 QThread使用单独的工作对象,因为它更容易允许工作线程和主线程之间通过信号和槽进行线程安全通信。您的示例的主要问题之一正是您试图在主线程之外执行与 GUI 相关的操作,而 Qt 不支持这种操作(因此会出现警告消息)。
如果您想从 GUI 启动、停止和暂停工作程序,则需要进行一些仔细的处理,以确保工作程序和线程在用户尝试关闭仍在运行的窗口时完全关闭。在下面的示例中,我在 closeEvent 中使用了一个简单的中止机制。 ;如果您想要更复杂的处理,您可以,例如 ignore()当工作线程仍在运行时关闭事件。按“开始”将启动/继续工作程序,按“停止”将暂停它。一旦工作进程完成,按“开始”将完全重新启动它(即它将返回到零):
class Worker(QtCore.QObject):
progress = QtCore.pyqtSignal(int)
finished = QtCore.pyqtSignal()
def __init__(self):
super().__init__()
self._paused = True
self._count = -1
def start(self):
self._paused = False
if self._count < 0:
print('Start')
self._run()
else:
print('Continue')
def stop(self, *, abort=False):
self._paused = True
if abort:
print('Abort')
self._count = -1
else:
print('Pause')
def _run(self):
self._count = 0
self._paused = False
while 0 <= self._count <= 100:
if not self._paused:
QtCore.QThread.msleep(100)
self._count += 1
self.progress.emit(self._count)
self.stop(abort=True)
self.finished.emit()
print('Finished')
class exampleprogram(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(exampleprogram, self).__init__(parent)
self.setupUi(self)
self.thread = QtCore.QThread(self)
self.worker = Worker()
self.worker.moveToThread(self.thread)
self.thread.started.connect(self.worker.start)
self.worker.finished.connect(self.thread.quit)
self.worker.progress.connect(self.progressBar.setValue)
self.pushButton_Start.clicked.connect(self.start)
self.pushButton_Stop.clicked.connect(self.stop)
def start(self):
if self.thread.isRunning():
self.worker.start()
else:
self.thread.start()
def stop(self):
if self.thread.isRunning():
self.worker.stop()
def closeEvent(self, event):
self.worker.stop(abort=True)
self.thread.quit()
self.thread.wait()
关于python - PyQt5 : start, 停止并暂停带有进度更新的线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72375050/