【问题标题】:QDialog with loading bar is not displaying on time带有加载栏的 QDialog 未按时显示
【发布时间】:2021-06-15 13:08:46
【问题描述】:

我有一个应用程序,它有一个 QMainWindow 和一个处理所有事件的后端控制器。来自 QMainWindow 的这些事件之一会发出一个信号,该信号会在控制器中调用此方法。

def add_files(self, file_paths):
    try:

        for file_path in file_paths:

            file_name = os.path.basename(file_path)

            "Some other working code here"

            self.silent_save()
            self.main_widget.update_file_display()

    except Exception as e:

        self.logger.error()

我还有一个 QDialog 类,其加载栏看起来像这样。

class FileLoadingScreen(QDialog, Ui_FileLoadingScreen):
    def __init__(self, loading_gif_path, parent=None):
        super(FileLoadingScreen, self).__init__(parent)

        self.setupUi(self)
        self.setWindowModality(QtCore.Qt.ApplicationModal)

        # Setting up the loading.gif animation.
        self.movie = QMovie(loading_gif_path)
        self.loading_label.setMovie(self.movie)

        self.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)
        self.setWindowFlags(QtCore.Qt.FramelessWindowHint)

    def start_animation(self, width, height, geometry):

        self.resize(width, height)
        self.setGeometry(geometry)
        self.movie.start()
        self.show()

    def stop_animation(self):

        self.movie.stop()
        self.close()

我尝试了多种调用 start_animation 方法的方法。使用另一个线程(定时器问题)调用 start_animation,从控制器方法调用它,从 QMainWindow 中调用它,使用从 QMainWindow 发射到控制器的信号调用它。由于明显的原因,线程方法根本不起作用,但所有其他方法都会产生相同的结果,加载对话框会显示,但只有在 add_files 方法完成执行后才会显示。我知道谁拥有主执行线程的执行控制权是个问题,但我没有想法。

【问题讨论】:

  • 假设后端控制器位于主线程中,for-loop 会阻塞主事件循环,直到文件加载完毕。如果您还没有这样做,您可以尝试运行在另一个线程上加载文件的 for 循环。
  • @Heike 有没有一种直接的方法可以让我在另一个线程中运行该循环,或者我需要创建一个工作类来传递它吗?
  • @BobFromBilling 请提供minimal reproducible example
  • @BobFromBilling 你需要一个单独的课程。
  • @musicamante 我想

标签: python pyqt5 python-3.6


【解决方案1】:

首先,我只想对所有发帖的人表示感谢,这是一次急需的健全性检查。以下是我的解决方案,但我不建议这样做,除非您像我一样受到预算和时间限制。理想情况下,我的控制器的 add_files 方法中的代码应该放在一个单独的帮助程序类中,该类在它自己的线程上运行,并且只是向控制器发出信号。但是,我的解决方案运行良好。

@pyqtSlot(list)
def add_files(self, file_paths):

    self.call_loading()

    t2 = Thread(target=self.start_file_copy, args=[file_paths])

    t2.start()

def start_file_copy(self, file_paths):

    try:

        for file_path in file_paths:

            file_name = os.path.basename(file_path)

            "Some worker code here"
            self.silent_save()
            self.main_widget.update_file_display()

        self.done_loading.emit()

    except Exception as e:

        self.logger.error()

def call_loading(self):

    self.file_loading_screen.start_animation(self.main_screen.width(), self.main_screen.height(), self.main_screen.geometry())

@pyqtSlot()
def close_loading(self):

    self.file_loading_screen.stop_animation()

【讨论】:

  • 我不明白预算/时间限制应该如何阻止您使用一个简单的基本类,该类只实现其run() 方法,这不仅更简单,而且更清晰(和更清洁)从模块化的角度来看。
  • 很简单,使用“这里的一些工作代码”部分中排除的必要代码来实现一个附加类将需要大量的返工和后续测试。正如我在回答中所说,我完全同意你的看法。如果可能的话,一个单独的 QRunnable 类或类似的类将是最好的解决方案。我不会直接批评,但那只是我。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多