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

时间:2017-10-11 00:34:20

标签: python multithreading pyqt5

我退休并自学编写代码。我正在开发一个程序,需要一个线程在后台运行(用PYQT5开发的GUI)所以我仍然可以使用GUI按钮(暂停,恢复,停止等)。我的线程数到10,我希望将步骤发送回进度条的setValue。那不行。我可以看到线程计数到10,我可以看到从线程返回的数据。只是无法移动进度条。  我花了最近两天的时间搜索互联网并进行了审核,并试图效仿许多例子。说实话,我不确定我理解答案 我已经创建了一个我在程序中看到的例子。在这个例子中,我在GUI中有一个带有两个按钮的进度条。 Start将启动线程,测试将在线程运行时打印出测试语句。我使用的是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.ServiceUnknown:任何.service文件都没有提供名称org.a11y.Bus   QObject:无法为位于不同线程中的父级创建子级。   (Parent是QApplication(0x26a1a58),父线程是QThread(0x26a6218),当前线程是ExecuteSession(0x28f4048)

我不是软件开发人员,这对我来说很新。我感谢任何我能得到的帮助,请...不要以为我什么都知道。请描述一下。谢谢!

1 个答案:

答案 0 :(得分:0)

由于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用作变量,因为它是预加载函数的名称,还有数千个其他名称。