QWidget не загружает дочерние элементы, когда также вызывается QRunnable - PullRequest
2 голосов
/ 17 апреля 2019

Я работаю в настольном приложении для обработки данных с Python 3.7 и PySide2, для которого требуется, чтобы я загружал данные из нескольких больших (около 250 тыс. Строк) файлов Excel в библиотеку обработки программы. Для этого я настроил в своем приложении простое всплывающее окно (называемое LoadingPopup), которое включает в себя вращающийся GIF и простой заголовок, а также некоторый код, который загружает данные из файлов Excel в глобальный объект с помощью панд. Обе эти вещи работают как задумано, когда запускаются сами по себе, но если мне удастся создать диалоговое окно загрузки и рабочий QRunnable в той же области моей кодовой базы, виджеты, содержащиеся в виджете загрузки (рисунок и простая подпись), просто не показывать.

Я попытался изменить родительский тип для моего виджета с 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. Мои ожидаемые результаты состоят в том, что я должен иметь возможность загрузки LoadingPopup с движением gif, а затем он должен закрыться, когда QRunnable завершит работу.

1 Ответ

0 голосов
/ 17 апреля 2019

Вы не должны вызывать метод run напрямую, так как у вас будет тяжелая задача, запущенная в потоке графического интерфейса, замораживающем его.Вы должны запустить его, используя 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()
...