当 QRunnable 也被调用时,QWidget 不加载 child 元素
QWidget not loading child elements when QRunnable is also called
我在使用 Python 3.7 和 PySide2 的数据处理桌面应用程序中工作,它需要我从几个大的(大约 250k 行)excel 文件中加载数据到程序的处理库中.为此,我在我的应用程序中设置了一个简单的弹出窗口(称为 LoadingPopup),其中包括一个旋转的 gif 和一个简单的标题,以及一些将数据从 excel 文件加载到全局 object 使用 pandas。当 运行 单独时,这两件事都按预期工作,但如果我碰巧在我的代码库的相同范围内创建一个加载对话框和一个 QRunnable worker,加载小部件中包含的小部件(一个 gif 和一个简单的caption) 根本不会显示。
我已经尝试将我的小部件的 parent 类型从 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 完成后关闭。
您不应直接调用 运行 方法,因为 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()
我在使用 Python 3.7 和 PySide2 的数据处理桌面应用程序中工作,它需要我从几个大的(大约 250k 行)excel 文件中加载数据到程序的处理库中.为此,我在我的应用程序中设置了一个简单的弹出窗口(称为 LoadingPopup),其中包括一个旋转的 gif 和一个简单的标题,以及一些将数据从 excel 文件加载到全局 object 使用 pandas。当 运行 单独时,这两件事都按预期工作,但如果我碰巧在我的代码库的相同范围内创建一个加载对话框和一个 QRunnable worker,加载小部件中包含的小部件(一个 gif 和一个简单的caption) 根本不会显示。
我已经尝试将我的小部件的 parent 类型从 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 完成后关闭。
您不应直接调用 运行 方法,因为 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()