QWidget也调用QRunnable时未加载子元素

时间:2019-04-17 20:21:44

标签: python python-3.x pyside2

我正在使用Python 3.7和PySide2在数据处理桌面应用程序中工作,在该应用程序上我需要将几个大(约25万行)excel文件中的数据加载到程序的处理库中。为此,我在应用程序中设置了一个简单的弹出窗口(称为LoadingPopup),其中包括一个旋转的gif和一个简单的标题,以及一些使用pandas将excel文件中的数据加载到全局对象中的代码。当它们单独运行时,这两种方法都能按预期工作,但是如果我碰巧在我的代码库的同一范围内创建了一个加载对话框和QRunnable worker,则加载小部件(一个gif和一个简单的标题)中包含的小部件将很简单不显示。

我尝试将我的窗口小部件的父类型从QDialog更改为QWidget,或者初始化窗口小部件内部和外部的弹出窗口(start()函数)。我对Qt5不太了解,所以我不知道该怎么办。


import sys, time, traceback

from PySide2.QtWidgets import *
from PySide2.QtCore import *
from PySide2.QtGui import *

from TsrUtils import PathUtils


class WorkerSignals(QObject):
    finished = Signal()
    error = Signal(tuple)
    result = Signal(object)

class TsrWorker(QRunnable):

    def __init__(self, fn, *args, **kwargs):
        super(TsrWorker, self).__init__()
        self.fn = fn
        self.args = args
        self.kwargs = kwargs
        self.signals = WorkerSignals()

    @Slot()
    def run(self):
        try:
            result = self.fn(*self.args, **self.kwargs)
        except:
            traceback.print_exc()
            exctype, value = sys.exc_info()[:2]

            self.signals.error.emit((exctype, value, traceback.format_exc()))
        else:
            self.signals.result.emit(result)
        finally:
            self.signals.finished.emit()

class LoadingPopup(QWidget):
    def __init__(self):
        super().__init__()

        self.message = "Cargando"
        self.setMinimumSize(350,300)

        self.setWindowIcon(\
            QIcon(PathUtils.ruta_absoluta('resources/icons/tsr.png')))

        self.setWindowTitle(self.message)

        self.layout = QVBoxLayout(self)
        self.setLayout(self.layout)

        self.movie = QMovie(self)
        self.movie.setFileName("./resources/img/spinner.gif")
        self.movie.setCacheMode(QMovie.CacheAll)
        self.movie.start()

        self.loading = QLabel(self)
        self.loading.setMovie(self.movie)
        self.loading.setAlignment(Qt.AlignCenter)
        self.layout.addWidget(self.loading)

        self.lbl = QLabel(self.message, self)
        self.lbl.setAlignment(Qt.AlignCenter)
        self.lbl.setStyleSheet("font: 15pt")
        self.layout.addWidget(self.lbl)

class MyMainApp(QApplication):
    def __init__(self, args):
        super().__init__()

        self.l = LoadingPopup()
        self.l.show()

        w = TsrWorker(time.sleep, 5)
        w.signals.finished.connect(self.terminado)
        w.run()

    def terminado(self):
        print('timer finished')
        self.l.hide()

if __name__ == '__main__':

    app = MyMainApp(sys.argv)

    sys.exit(app.exec_())

在示例中,我已经使用time.sleep函数更改了应用程序的实际数据加载部分。我的预期结果是,我应该能够通过gif移动显示LoadingPopup,然后一旦QRunnable完成,它将关闭。

1 个答案:

答案 0 :(得分:0)

您不应直接调用run方法,因为您将在GUI线程上运行繁重的任务以冻结它。您必须使用QThreadPool启动它:

class MyMainApp(QApplication):
    def __init__(self, args):
        super().__init__()
        self.l = LoadingPopup()
        self.l.show()
        w = TsrWorker(time.sleep, 5)
        w.signals.finished.connect(self.terminado)
        # w.run()
        QThreadPool.globalInstance().start(w) # <---

    def terminado(self):
        print('timer finished')
        self.l.hide()