PyQt5 无法从线程更新进度条并收到错误“无法为位于不同线程中的父级创建子级" [英] PyQt5 cannot update progress bar from thread and received the error "Cannot create children for a parent that is in a different thread"

查看:132
本文介绍了PyQt5 无法从线程更新进度条并收到错误“无法为位于不同线程中的父级创建子级"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我退休了,正在自学编写代码.我正在开发一个需要线程在后台运行的程序(用 PYQT5 开发的 GUI),所以我仍然可以使用 GUI 按钮(暂停、恢复、停止等).我将线程计数到 10,并且我希望将步骤发送回进度条的 setValue.那是行不通的.我可以看到线程计数到 10,并且可以看到从线程返回的数据.只是无法让进度条移动.我花了两天时间在互联网上搜索并查看并尝试遵循许多示例.老实说,我不确定我是否理解答案.
我已经创建了一个我在我的程序中看到的例子.在这个例子中,我在 GUI 中有一个带有两个按钮的进度条.Start 将启动线程,而 test 将在线程运行时打印出测试语句.我正在使用 Designer,因此 GUI 位于单独的文件中.
我什至不确定我在搜索中是否正确提问.我决定发布我经常看到的错误,但希望您能在运行代码时看到发生了什么.

I am retired and teaching myself to write code. I am working on a program that requires a thread to operate in the background (GUI developed with PYQT5) so I can still use the GUI buttons (to pause, resume, stop, etc.). I have the thread counting to 10, and I want the steps sent back to the progress bar's setValue. That is not working. I can see the thread counting to 10 and I can see the data coming back from the thread. Just can't get the progress bar to move. I have spent the last two days searching the internet and have reviewed and tried to follow many examples. To be honest, I am not sure I understand the answers.
I have crated an example of what I am seeing in my program. In this example I have a progress bar in a GUI with two buttons. Start will start the thread and test will just print out test statements while the thread is running. I am using Designer, so the GUI is in a separate file.
I am not even sure if I am asking the questions correctly in my searches. I decided to post in the error I see a lot, but hopefully you can see what is happening when you run the code.

主程序

#!/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)

(python3:11942): WARNING: Error retrieving accessibility bus address: org.freedesktop.DBus.Error.ServiceUnknown: The name org.a11y.Bus was not provided by any .service files QObject: Cannot create children for a parent that is in a different thread. (Parent is QApplication(0x26a1a58), parent's thread is QThread(0x26a6218), current thread is ExecuteSession(0x28f4048)

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

I am not a software developer, so much of this is new to me. I appreciate any help I can receive, and please...don't assume I know anything. Please be descriptive. Thank you!

推荐答案

你的代码有几个错误,因为 PyQt 有一些最低规则:

Your code has several errors since PyQt has certain minimum rules:

  • 创建GUI应用程序的线程称为GUI线程,因为必须创建并激活任何图形组件,但是您在QThread内部创建了不必要的RPTApp,我说不必要,因为线程是在RPTApp内部创建的所以没有必要创建另一个.

  • The thread where the GUI application is created is called GUI thread because there must be created and live any graphic component, but you are creating unnecessary RPTApp inside the QThread, I say unnecessary since the thread is created inside RPTApp so it does not it is necessary to create another.

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

Another error is in the emission of the signal in the wire, you do not have to call the function that uses the data that emits the signal but you must connect it to the slot. The application will be in charge of transporting the data and invoking the slot.

以下部分更正了以上所有内容:

All of the above is corrected in the following section:

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 作为变量,因为它是预加载函数的名称,还有成千上万个其他名称.

这篇关于PyQt5 无法从线程更新进度条并收到错误“无法为位于不同线程中的父级创建子级"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆