简体   繁体   English

PyQt5:如何在QThread和某些子类之间“通信”?

[英]PyQt5: How to 'communicate' between QThread and some sub-class?

To this question I am referring to the answer from @eyllanesc in PyQt5: How to scroll text in QTextEdit automatically (animational effect)? 对于这个问题,我指的是PyQt5中@eyllanesc的答案:如何在QTextEdit中自动滚动文本(动画效果)?

There @eyllanesc shows how to make the text auto scrolls smoothly using verticalScrollBar() . @eyllanesc展示了如何使用verticalScrollBar()使文本自动平滑滚动。 It works great. 效果很好。

For this question, I have added some extra lines, to use QThread to get the text. 对于这个问题,我添加了一些额外的行,以使用QThread来获取文本。

What I want to achieve here: to let the QThread class 'communicate' with the AnimationTextEdit class , so that the scrolling time can be determined by the text-length. 我在这里想要实现的是:QThread classAnimationTextEdit class QThread class “通信”,以便滚动时间可以由文本长度确定。 So that the programm stops, when the scrolling process ends. 因此,当滚动过程结束时,程序将停止。

I must say it is very very tricky task for me. 我必须说这对我来说是非常棘手的任务。 I would like to show the programm flow first, as I imagined. 如我所想,我想首先展示程序流程。

在此处输入图片说明

UPDATE: My code is as follows. 更新:我的代码如下。 It works, but... 它有效,但是...

Problem with the code: when the text stops to scroll, the time.sleep() still works. 代码问题:当文本停止滚动时, time.sleep()仍然有效。 The App wait there till time.sleep() stops. 应用程序在那里等待,直到time.sleep()停止。

What I want to get: When the text stops to scroll, the time.sleep() runs to its end value. 我想要得到的是:当文本停止滚动时, time.sleep()运行到其最终值。

from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
import time
import sqlite3


class AnimationTextEdit(QTextEdit):
    # signal_HowLongIsTheText = pyqtSignal(int)  # signal to tell the QThread, how long the text is

    def __init__(self, *args, **kwargs):
        QTextEdit.__init__(self, *args, **kwargs)
        self.animation = QVariantAnimation(self)
        self.animation.valueChanged.connect(self.moveToLine)

    # def sent_Info_to_Thread(self):
    #     self.obj_Thread = Worker()
    #     self.signal_HowLongIsTheText.connect(self.obj_Thread.getText_HowLongIsIt)
    #     self.signal_HowLongIsTheText.emit(self.textLength)
    #     self.signal_HowLongIsTheText.disconnect(self.obj_Thread.getText_HowLongIsIt)


    @pyqtSlot()
    def startAnimation(self):
        self.animation.stop()
        self.animation.setStartValue(0)

        self.textLength = self.verticalScrollBar().maximum()
        # self.sent_Info_to_Thread()


        self.animation.setEndValue(self.textLength)
        self.animation.setDuration(self.animation.endValue()*4)
        self.animation.start()

    @pyqtSlot(QVariant)
    def moveToLine(self, i):
        self.verticalScrollBar().setValue(i)



class Worker(QObject):
    finished = pyqtSignal()
    textSignal = pyqtSignal(str)

    # @pyqtSlot(int)
    # def getText_HowLongIsIt(self, textLength):
    #     self.textLength = textLength

    @pyqtSlot()
    def getText(self):
        longText = "\n".join(["{}: long text - auto scrolling ".format(i) for i in range(100)])

        self.textSignal.emit(longText)

        time.sleep(10)
        # time.sleep(int(self.textLength / 100))
        # My question is about the above line: time.sleep(self.textLength)
        # Instead of giving a fixed sleep time value here,
        # I want let the Worker Class know,
        # how long it will take to scroll all the text to the end.

        self.finished.emit()


class MyApp(QWidget):
    def __init__(self):
        super(MyApp, self).__init__()
        self.setFixedSize(600, 400)
        self.initUI()
        self.startThread()

    def initUI(self):
        self.txt = AnimationTextEdit(self)
        self.btn = QPushButton("Start", self)

        self.layout = QHBoxLayout(self)
        self.layout.addWidget(self.txt)
        self.layout.addWidget(self.btn)

        self.btn.clicked.connect(self.txt.startAnimation)

    def startThread(self):
        self.obj = Worker()
        self.thread = QThread()

        self.obj.textSignal.connect(self.textUpdate)
        self.obj.moveToThread(self.thread)
        self.obj.finished.connect(self.thread.quit)
        self.thread.started.connect(self.obj.getText)
        self.thread.finished.connect(app.exit)
        self.thread.start()

    def textUpdate(self, longText):
        self.txt.append(longText)
        self.txt.moveToLine(0)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MyApp()
    window.show()
    sys.exit(app.exec_())

Thanks for the help and hint. 感谢您的帮助和提示。 What have I done wrong? 我做错了什么?

Although in the animation the duration is established it is necessary to understand that this is not exact, this could vary for several reasons, so calculating using the sleep to wait for it to end in a certain time and just closing the application may fail. 尽管在动画中确定了持续时间,但有必要了解这不是很精确,但是由于多种原因,它可能会有所不同,因此使用睡眠进行计算以等待它在特定时间内结束,并且仅关闭应用程序可能会失败。

If your main objective is that when the animation is finished the program execution is finished then you must use the finished QVariantAnimation signal to finish the execution of the thread, this signal is emited when it finishes executing. 如果您的主要目的是当动画完成时程序执行完成,那么您必须使用完成的QVariantAnimation信号来完成线程的执行,该信号在完成执行时发出。

class AnimationTextEdit(QTextEdit):
    def __init__(self, *args, **kwargs):
        QTextEdit.__init__(self, *args, **kwargs)
        self.animation = QVariantAnimation(self)
        self.animation.valueChanged.connect(self.moveToLine)

    @pyqtSlot()
    def startAnimation(self):
        self.animation.stop()
        self.animation.setStartValue(0)
        self.textLength = self.verticalScrollBar().maximum()
        self.animation.setEndValue(self.textLength)
        self.animation.setDuration(self.animation.endValue()*4)
        self.animation.start()

    @pyqtSlot(QVariant)
    def moveToLine(self, i):
        self.verticalScrollBar().setValue(i)


class Worker(QObject):
    textSignal = pyqtSignal(str)
    @pyqtSlot()
    def getText(self):
        longText = "\n".join(["{}: long text - auto scrolling ".format(i) for i in range(100)])
        self.textSignal.emit(longText)


class MyApp(QWidget):
    def __init__(self):
        super(MyApp, self).__init__()
        self.setFixedSize(600, 400)
        self.initUI()
        self.startThread()

    def initUI(self):
        self.txt = AnimationTextEdit(self)
        self.btn = QPushButton("Start", self)

        self.layout = QHBoxLayout(self)
        self.layout.addWidget(self.txt)
        self.layout.addWidget(self.btn)

        self.btn.clicked.connect(self.txt.startAnimation)

    def startThread(self):
        self.obj = Worker()
        self.thread = QThread()

        self.obj.textSignal.connect(self.textUpdate)
        self.obj.moveToThread(self.thread)
        self.txt.animation.finished.connect(self.thread.quit)
        self.thread.started.connect(self.obj.getText)
        self.thread.finished.connect(app.exit)
        self.thread.start()

    def textUpdate(self, longText):
        self.txt.append(longText)
        self.txt.moveToLine(0)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MyApp()
    window.show()
    sys.exit(app.exec_())

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

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