PhilFPH
PhilFPH

Reputation: 13

qsplashscreen doesn't displays properly until app.processEvents() is called twice

PyQT4.11
Python 2.7

I have been trying to create a splash screen to display a loading message when a specific tab is selected. When app.processEvents() is called I get a grey box displayed instead of the image, but if I add a second app.processEvents() after the first function is called the correct image is displayed until the splash is closed on completion.

I have played around with sleep timers, repainting, updating, closing and reshowing the tab and tabwidget with mixed results, on the rare occasion it will work but more often than not it won't. Can anyone shed any light on what I am missing?

import sys
from PyQt4 import QtCore, QtGui

class splashTest(QtGui.QDialog):
    def __init__(self, parent=None):
        super(splashTest, self).__init__(parent)

        self.setGeometry(000,000,800,400)
        self.tabWidget = QtGui.QTabWidget(self)
        self.tabWidget.setGeometry(QtCore.QRect(0, 0, 500, 500))
        self.tabWidget.setObjectName("tabWidget")
        self.tab1 = QtGui.QWidget()
        self.tab2 = QtGui.QWidget()
        self.tab3 = QtGui.QWidget()

        self.tabWidget.addTab(self.tab1, "tab1")
        self.tabWidget.addTab(self.tab2, "tab2")
        self.tabWidget.addTab(self.tab3, "Click Me")

        self.tabWidget.setCurrentIndex(1)

        self.tabWidget.currentChanged.connect(self.whichTabIsSelected)


def whichTabIsSelected(self):
    if self.tabWidget.currentIndex() == 2:
        splash_pix = QtGui.QPixmap('splash.png')
        splash = QtGui.QSplashScreen(splash_pix, QtCore.Qt.WindowStaysOnTopHint)
        splash.setMask(splash_pix.mask())
        splash.show()
        app.processEvents()
        self.timeConsumingFunction()
        app.processEvents() 
        self.timeConsumingFunction()

        splash.finish(self.tabWidget)

    else:
        pass

def timeConsumingFunction(self):
    b = 0
    for a in range(100000000):
        b += a
    print (b)


if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    myapp = splashTest()
    myapp.show()
    sys.exit(app.exec_())

Upvotes: 1

Views: 720

Answers (1)

eyllanesc
eyllanesc

Reputation: 243937

The problem is that you are running the heavy task in the main thread blocking the event loop of the GUI, and this causes the window to freeze, and you are forcing the update using QApplication::processEvents(), instead the correct solution is to execute that task heavy on another thread.

import sys
from PyQt4 import QtCore, QtGui
import threading

class splashTest(QtGui.QDialog):
    finished = QtCore.pyqtSignal()

    def __init__(self, parent=None):
        super(splashTest, self).__init__(parent)

        self.setGeometry(000,000,800,400)
        self.tabWidget = QtGui.QTabWidget(self)
        self.tabWidget.setGeometry(QtCore.QRect(0, 0, 500, 500))
        self.tabWidget.setObjectName("tabWidget")
        self.tab1 = QtGui.QWidget()
        self.tab2 = QtGui.QWidget()
        self.tab3 = QtGui.QWidget()

        self.tabWidget.addTab(self.tab1, "tab1")
        self.tabWidget.addTab(self.tab2, "tab2")
        self.tabWidget.addTab(self.tab3, "Click Me")

        self.tabWidget.setCurrentIndex(1)
        self.tabWidget.currentChanged.connect(self.whichTabIsSelected)

    @QtCore.pyqtSlot(int)
    def whichTabIsSelected(self, index):
        if index == 2:
            splash_pix = QtGui.QPixmap('splash.png')
            splash = QtGui.QSplashScreen(self, splash_pix, QtCore.Qt.WindowStaysOnTopHint)
            splash.setMask(splash_pix.mask())
            splash.show()
            for _ in range(2):
                loop = QtCore.QEventLoop()
                self.finished.connect(loop.quit)
                threading.Thread(target=self.timeConsumingFunction).start()
                loop.exec_()
            splash.finish(self.tabWidget)
            splash.close()

    def timeConsumingFunction(self):
        b = 0
        for a in range(100000000):
            b += a
        print (b)
        self.finished.emit()


if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    myapp = splashTest()
    myapp.show()
    sys.exit(app.exec_())

Upvotes: 1

Related Questions