【问题标题】:Using QThread for a throbber将 QThread 用于 throbber
【发布时间】:2015-08-12 11:35:42
【问题描述】:

我想在启动某些操作时向我的 GUI 添加一个 throbber。

这是我的脚本:

class StartTask(QtCore.QThread):
    taskStarted = pyqtSignal()
    def run(self):
        self.taskStarted.emit()

class StopTask(QtCore.QThread):
    taskStopped = pyqtSignal()
    def run(self):
        self.taskStopped.emit()

class Projet(object):

    def __init__(self):
        self.movie = '' # throbber
        self.startTask = StartTask()
        self.startTask.taskStarted.connect(self.startThrobber)
        self.stopTask = StopTask()
        self.stopTask.taskStopped.connect(self.stopThrobber)

    def startThrobber(self):
        # set up the movie screen on a label
        self.movie_screen = QLabel()
        # expand and center the label
        main_layout = QVBoxLayout()
        main_layout.addWidget(self.movie_screen)
        ui.throbberTab2.setLayout(main_layout)
        # use an animated gif file you have in the working folder
        byteF = QByteArray()
        movie = QMovie("D:\Various\Images\loader.gif", byteF)
        movie.setCacheMode(QMovie.CacheAll)
        movie.setSpeed(100)
        self.movie_screen.setMovie(movie)
        movie.start()

        return movie

    def stopThrobber(self):
        movie1 = self.startThrobber()
        movie1.stop()

    def goAction(self):
        if ui.chkbox.isChecked():
            self.startTask.taskStarted.connect(self.startThrobber)
            os.system(r'..........') # script launched
            self.stopTask.taskStopped.connect(self.stopThrobber)
            QMessageBox.information(self.popup(), "Information", "It works!")

由于我是第一次使用线程,所以我找不到哪里出了问题,哪里出了问题..

这没有结果,即使我认为我离正确的代码并不太远。

我已经设法让 throbber 出现,但不是在正确的时刻(当时线程不工作)。

【问题讨论】:

  • 你为什么要使用线程?似乎什么都不需要线程。您创建的线程在启动时仅发出一个信号,仅此而已(线程结束)。线程用于长时间运行的后台任务,这似乎不是您在这里所做的。
  • 好的。那么如何使用颤动器呢?因为它不是在脚本运行时设置的,它仅在脚本运行完成时才打开。我认为有一种特殊的方法可以做到这一点?

标签: python user-interface pyqt qthread throbber


【解决方案1】:

我没有使用QThread,而是使用subprocess,效果很好。 不过我不知道有什么区别,比如一个比另一个“更好”,或者它们是否有微小的差异等,但它确实有效!

【讨论】:

    【解决方案2】:

    您的代码存在一个问题,即对 os.system() 的调用(可能是长时间运行,因此需要一个 throbber)正在主线程中执行。这会阻止 GUI(和 Qt 事件循环)。 QMovie 需要一个正常运行的事件循环才能正确设置动画。因此,使用您当前的代码,您无法使颤动显示为动画,因为这需要响应式 GUI(或更准确地说是响应式事件循环)。

    顺便说一句,您也不能直接从线程调用 GUI 方法。您只能从辅助线程将事件发送回主线程(就像您当前所做的那样)。这意味着您不能QMovie 卸载到线程。

    因此,您需要将对os.system() 的调用卸载到线程中,并在完成时发出信号。该信号可以连接到停止颤动的插槽。在启动线程之前,只需直接调用您现有的startThrobber() 方法即可开始跳动。

    这样,您的 UI 保持响应(包括正确显示颤动动画),同时线程处理阻塞所有内容的长时间运行的进程。

    【讨论】:

    • 哦,是的,我没想到会这样做!谢谢,我会更正我的代码!!
    • 我已经尝试过了,但我仍然遇到同样的问题。在我调用线程之前,throbber 不会开始,而且,throbber 不会停止(即使有一个 movie.stop() 命令)..
    • @guy16 现在发布新问题可能更容易,因为您采用了不同的方法,minimilistic working example 展示了新问题。
    • "这个信号可以连接到一个停止跳动的槽。在启动线程之前,直接调用你现有的 startThrobber() 方法来启动跳动。"那是我遇到麻烦的地方。我无法使两者都起作用,要么是颤动会开始但不会停止,要么是相反。因为在线程中,我有 subprocess.Popen,然后是一个停止 throbber 的信号,它同时执行这 2 个动作.. 如何在不使用计时器的情况下让信号等待发射?
    • @guy16 您正在执行的命令需要多长时间才能正常运行? (也就是如果你从命令行运行它)
    猜你喜欢
    • 2015-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多