为了账号安全,请及时绑定邮箱和手机立即绑定

Python-父代和多线程问题

Python-父代和多线程问题

翻翻过去那场雪 2021-03-29 13:10:58
我正在学习PyQT和多线程,我想在这里需要帮助。在我的代码中,我有Tool一个class和一个thread TaskThread。从线程中,我调用一个函数dummy_function,该函数执行进度条在GUI中显示的过程。当dummy_function完成后,我想在GUI打印一条消息,通过调用self.outputText.setText("Hello")。但是,出现以下错误:AttributeError:'TaskThread'对象没有属性'outputText'我尝试的第一件事是将以下行添加到我的onStart函数中:...self.myLongTask.output_dt = self.outputText...然后,在中TaskThread,我dummy_function通过以下方式更改调用:...dummy_function(self, start_datetime_unix, end_datetime_unix, self.output_dt) ...最后,我通过添加以下新参数来更改我的dummy_function:def dummy_function(self, start_datetime_unix, end_datetime_unix, output_text):     # Dummy function, just to simulate a task. It takes parameters just for testing.    result = start_datetime_unix * end_datetime_unix     # Pre-steps for mapping from one range to other (progress-bar)    OldMax = 99999    OldMin = 1    NewMax = 100    NewMin = 1    OldRange = (OldMax - OldMin)    NewRange = (NewMax - NewMin)        u = 1    for i in range (OldMax):        u = i*2        OldValue = i        print OldValue        NewValue = (((OldValue - OldMin) * NewRange) / OldRange) + NewMin        print "NEW VALUE: ", NewValue        self.emit(QtCore.SIGNAL('CPU_VALUE'), NewValue)    output_text.setText("Hello")现在,到达终点时,程序将关闭,并显示以下错误:QObject:无法为处于不同线程中的父级创建子级。(父母是QTextDocument(0xf13a60),父母的线程是QThread(0xc6f180),当前线程是TaskThread(0xee0740)为了尝试该程序,我升级了GUInterface,因此如有必要,您可以尝试一下。
查看完整描述

1 回答

?
收到一只叮咚

TA贡献1821条经验 获得超4个赞

您得到的第一个是由于TaskThread没有outputText属性而引起的,并且您的解决方案在某种程度上是正确的,因为它解决了第一个问题,但是还有另一个问题,Qt禁止从另一个生成该线程的线程直接更新该GUI。问题 。Qt表示如果您要使用其他线程的信息更新GUI,您必须使用信号或信号QMetaObject,在这种情况下,我将通过创建一个signal被调用来解决它textChanged,它将与的setText()方法连接outputText。


另一方面,我看到您使用的是旧的连接样式:


self.connect(self.myLongTask, QtCore.SIGNAL('CPU_VALUE'), self.onProgress)

尽管不再建议您仍然可以使用该样式,但最好还是使用新语法。


最后,连接到信号的功能称为插槽,因此建议使用装饰器@QtCore.pyqtSlot(...),此方法可最大程度地减少资源消耗。


import sys

import datetime

import time


from PyQt4 import QtCore, QtGui, uic

from PyQt4.QtCore import *

from PyQt4.QtGui import *


# Link to GUI

qtCreatorFile = "GUInterface.ui"


Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile)


def time_converter_to_unix(start_datetime, end_datetime):

    # Convert QTimeEdit to UNIX Timestamp (int, msec included), and then to float

    start_datetime_unix_int = start_datetime.toMSecsSinceEpoch ()

    start_datetime_unix = (float(start_datetime_unix_int) / 1000)


    end_datetime_unix_int = end_datetime.toMSecsSinceEpoch ()

    end_datetime_unix = (float(end_datetime_unix_int) / 1000)


    return start_datetime_unix, end_datetime_unix


def dummy_function(self, start_datetime_unix, end_datetime_unix): 

    # Dummy function, just to simulate a task. It takes parameters just for testing.

    result = start_datetime_unix * end_datetime_unix 


    # Pre-steps for mapping from one range to other (progress-bar)

    OldMax = 99999

    OldMin = 1

    NewMax = 100

    NewMin = 1


    OldRange = (OldMax - OldMin)

    NewRange = (NewMax - NewMin)    


    u = 1

    for i in range (OldMax):

        u = i*2


        OldValue = i

        print(OldValue)

        NewValue = (((OldValue - OldMin) * NewRange) / OldRange) + NewMin

        print("NEW VALUE: ", NewValue)


        self.cpuValueChanged.emit(NewValue)


    self.textChanged.emit("Hello")


class Tool(QtGui.QMainWindow, Ui_MainWindow):

    def __init__(self, parent = None):


        # Setting-ip UI

        QtGui.QMainWindow.__init__(self)

        Ui_MainWindow.__init__(self)

        self.setupUi(self)


        # Button Action

        self.runButton.clicked.connect(self.onStart)


        # Progress Bar and Label. At the begining, the bar is at 0

        self.progressBar.setValue(0)

        self.progressBar.setRange(0,100)

        self.resultLabel.setText("Waiting...")  


        ####################################

        #TEST: Thread for progress bar

        self.myLongTask = TaskThread()

        self.myLongTask.cpuValueChanged.connect(self.progressBar.setValue)

        self.myLongTask.textChanged.connect(self.outputText.setText)

        self.myLongTask.taskFinished.connect(self.onFinished)

        ####################################        


    @QtCore.pyqtSlot()

    def onStart(self):    

        self.progressBar.reset()

        self.resultLabel.setText("In progress...")        

        print("(onStart)In progress mode executed")


        print("(onStart)INITIALIZE THREAD")

        self.myLongTask.start()     

        print("(onStart)THREAD EXECUTED")


        self.myLongTask.start_dt = self.startTime.dateTime() # <----

        self.myLongTask.end_dt = self.endTime.dateTime()     # <----     


    @QtCore.pyqtSlot()

    def onFinished(self):

        # Stop the pulsation when the thread has finished

        print("(onFinished) executed")

        self.progressBar.setRange(0,1)

        self.progressBar.setValue(1)

        self.resultLabel.setText("Done")        


class TaskThread(QtCore.QThread):

    cpuValueChanged = QtCore.pyqtSignal(int)  

    taskFinished = QtCore.pyqtSignal()

    textChanged = QtCore.pyqtSignal(str)


    def __del__(self):

        self.wait()


    def run(self):  

        # First, we read the times from the QDateTime elements in the interface      

        print("Getting times...")

        start_datetime_unix, end_datetime_unix = time_converter_to_unix(self.start_dt, self.end_dt)


        # Then, we put these values in my_function

        print("Executing function...")

        dummy_function(self, start_datetime_unix, end_datetime_unix) 


        # To finish, we execute onFinished.

        print("Finishing thread...")

        self.taskFinished.emit()


def main():

    app = QtGui.QApplication(sys.argv)

    window = Tool()

    window.show()

    sys.exit(app.exec_())


if __name__ == '__main__':

    main()



查看完整回答
反对 回复 2021-04-13
  • 1 回答
  • 0 关注
  • 170 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号