PyQt5 无法从线程更新进度条,并收到错误"Cannot create children for a parent that is in a different thread"



我退休了,正在自学编写代码。我正在开发一个程序,该程序需要一个线程在后台操作(使用PYQT5开发的GUI),这样我仍然可以使用GUI按钮(暂停、恢复、停止等)。我的线程计数为10,我希望将步骤发送回进度条的setValue。这是行不通的。我可以看到线程计数到10,我可以看到从线程返回的数据。只是无法移动进度条。在过去的两天里,我一直在互联网上搜索,并复习了许多例子。老实说,我不确定我是否理解答案
我列举了一个我在节目中看到的例子。在这个例子中,我在GUI中有一个进度条,它有两个按钮。Start将启动线程,test将在线程运行时打印出测试语句。我使用的是Designer,所以GUI在一个单独的文件中
我甚至不确定我在搜索中问的问题是否正确。我决定发布我看到的很多错误,但希望你能在运行代码时看到发生了什么。

主程序

#!/usr/bin/env python3
import sys, sqlite3, os.path, string, time
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, 
QProgressBar
from PyQt5.QtCore import pyqtSlot, QObject, QThread, pyqtSignal
from Thread_Test import Ui_MainWindow
class ExecuteSession(QThread):
PBValueSig = pyqtSignal(int)
def __init__(self, dur=0):
QThread.__init__(self)
self.dur = dur
def __del__(self):
self.wait()
def run(self):
i = 0
while i <= self.dur:
self.RPTApp = RPTApp()
print(i)
i = i + 1
self.PBValueSig.emit(self.RPTApp.updateProgressBar(i))    
time.sleep(1)

class RPTApp(QMainWindow, Ui_MainWindow):

def __init__(self, parent=None):
super(RPTApp, self).__init__(parent)
self.setupUi(self)
self.pushButton.clicked.connect(self.PB)
self.pushButton_2.clicked.connect(self.PB2)
def PB2(self):
print("TEST")

def PB(self):
dur = 10
self.progressBar.setMinimum(0)
self.progressBar.setMaximum(dur)
self.progressBar.setValue(0)
#thread
self.exeThread = ExecuteSession(dur)
self.exeThread.start()        

@pyqtSlot(int)
def updateProgressBar(self, int):
print("INT + " +str(int))
#self.classES.PBValueSig.connect(self.progressBar.setValue)
self.progressBar.setValue(int)
def main():
app = QApplication(sys.argv)
window = RPTApp()
window.show()
app.exec_()    

if __name__ == '__main__':
main()

这是GUI代码:

# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'Thread_Test.ui'
#
# Created by: PyQt5 UI code generator 5.7
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(640, 480)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.progressBar = QtWidgets.QProgressBar(self.centralwidget)
self.progressBar.setGeometry(QtCore.QRect(90, 320, 471, 23))
self.progressBar.setProperty("value", 24)
self.progressBar.setObjectName("progressBar")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(270, 140, 91, 29))
self.pushButton.setObjectName("pushButton")
self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_2.setGeometry(QtCore.QRect(270, 200, 91, 29))
self.pushButton_2.setObjectName("pushButton_2")
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "START"))
self.pushButton_2.setText(_translate("MainWindow", "TEST"))

这是我收到的错误:

(python3:11942):警告:检索辅助功能总线地址时出错:org.freedesktop.DBus.Error.service未知:任何.service文件都没有提供org.a11.bus名称QObject:无法为处于不同线程中的父级创建子级。(父线程是QApplication(0x26a1a58),父线程是QThread(0x26a6218),当前线程是ExecuteSession(0x28f4048)

我不是软件开发人员,所以这对我来说很多都是新的。我很感激能得到的任何帮助,请。。。别以为我什么都知道。请描述。非常感谢。

由于PyQt有某些最低规则,您的代码有几个错误:

  • 创建GUI应用程序的线程被称为GUI线程,因为必须创建并运行任何图形组件,但您在QThread中创建了不必要的RPTApp,我认为这是不必要的,因为线程是在RPTApp中创建的,所以没有必要创建另一个。

  • 另一个错误是导线中信号的发射,您不必调用使用发射信号的数据的函数,但必须将其连接到插槽。应用程序将负责传输数据和调用插槽。

以上所有内容都在以下部分中进行了更正:

class ExecuteSession(QThread):
PBValueSig = pyqtSignal(int)
[...]
def run(self):
i = 0
while i <= self.dur:
print(i)
i = i + 1
self.PBValueSig.emit(i)
time.sleep(1)

class RPTApp(QMainWindow, Ui_MainWindow):
[..]
def PB(self):
dur = 10
self.progressBar.setMinimum(0)
self.progressBar.setMaximum(dur)
self.progressBar.setValue(0)
# thread
self.exeThread = ExecuteSession(dur)
self.exeThread.PBValueSig.connect(self.updateProgressBar)
self.exeThread.start()
@pyqtSlot(int)
def updateProgressBar(self, value):
print("INT + " + str(value))
self.progressBar.setValue(value)

注意:不建议使用int作为变量,因为它是预加载函数的名称,还有成千上万的其他名称

最新更新