繁体   English   中英

PyQt5 无法从线程更新进度条并收到错误“无法为不同线程中的父级创建子级”

[英]PyQt5 cannot update progress bar from thread and received the error “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()

这是图形用户界面代码:

# -*- 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.ServiceUnknown:名称 org.a11y.Bus 未由任何 .service 文件提供 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 作为变量,因为它是预加载函数的名称,还有成千上万个其他名称。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM