如何在 Pyqt5 中没有按钮的情况下从 SplashScreen 打开 MainWindow?

How to open MainWindow from a SplashScreen without button in Pyqt5?

我正在尝试创建一个加载屏幕,因为我的 MainWindow 需要超过 10 秒才能打开,只要我有一个加载屏幕就可以了。

我这里有一些代码,当我 运行 它时,它会打开一个加载屏幕。

加载屏幕弹出后,我希望它立即尝试打开主窗口。 (在我实际的应用程序中,这需要 10 秒才能打开) 我已经使用 time.sleep 来模拟我的实际程序打开所需的时间,因为这只是供您阅读的较小代码。但是我的真实代码不会包含任何睡眠,它自然需要 10 秒才能加载。

我怎样才能让它在我的加载屏幕可见时立即打开主窗口?目前我还没有要求它做任何事情,加载屏幕只是打开而已。

我需要什么额外的代码才能打开 MainWindow? 理想情况下,我想在发生这种情况时更新进度条,但现在这不是必需的我只想知道如何从加载屏幕立即打开 MainWindow,谢谢。

from PyQt5 import QtCore, QtGui, QtWidgets
import time   

class Ui_SplashScreen(object):    
    def setupUi(self, SplashScreen):
        SplashScreen.setObjectName("SplashScreen")
        SplashScreen.resize(800, 600)
        self.centralwidget = QtWidgets.QWidget(SplashScreen)
        self.centralwidget.setObjectName("centralwidget")
        self.progressBar = QtWidgets.QProgressBar(self.centralwidget)
        self.progressBar.setGeometry(QtCore.QRect(190, 220, 461, 91))
        self.progressBar.setProperty("value", 24)
        self.progressBar.setObjectName("progressBar")
        SplashScreen.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(SplashScreen)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
        self.menubar.setObjectName("menubar")
        SplashScreen.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(SplashScreen)
        self.statusbar.setObjectName("statusbar")
        SplashScreen.setStatusBar(self.statusbar)   
        self.retranslateUi(SplashScreen)
        QtCore.QMetaObject.connectSlotsByName(SplashScreen)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        time.sleep(10)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(310, 180, 341, 161))
        font = QtGui.QFont()
        font.setPointSize(40)
        self.label.setFont(font)
        self.label.setObjectName("label")
        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.label.setText(_translate("MainWindow", "MY APP"))

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    SplashScreen = QtWidgets.QMainWindow()
    ui = Ui_SplashScreen()
    ui.setupUi(SplashScreen)
    SplashScreen.show()
    sys.exit(app.exec_())

您不应修改 pyuic 生成的代码,因此您必须重新创建那些文件,我的解决方案将是 splash_ui.py 和 main_ui.py.

想法是耗时的任务不应该 运行 在主线程中,而是在辅助线程中,并在它开始和结束时发出显示和隐藏闪屏的信号。

import threading
import sys

from PyQt5.QtCore import QObject, pyqtSignal
from PyQt5.QtWidgets import QApplication, QMainWindow

from main_ui import Ui_MainWindow
from splash_ui import Ui_SplashScreen

def long_running_function():
    import time

    time.sleep(10)

class Worker(QObject):
    started = pyqtSignal()
    finished = pyqtSignal()

    def start(self):
        threading.Thread(target=self._execute, daemon=True).start()

    def _execute(self):
        self.started.emit()
        # FIXME
        long_running_function()
        self.finished.emit()


class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)


class SplashScreen(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.ui = Ui_SplashScreen()
        self.ui.setupUi(self)

def main():
    app = QApplication(sys.argv)

    splash_screen = SplashScreen()
    main_window = MainWindow()

    worker = Worker()
    worker.started.connect(splash_screen.show)
    worker.finished.connect(splash_screen.close)    
    worker.finished.connect(main_window.show)
    worker.start()

    sys.exit(app.exec_())