1

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_())
PhilFPH
  • 13
  • 4

1 Answers1

1

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_())
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Although this example worked perfectly in my test code I couldn't get it to work in my app. After much messing about I have finally got it working by totally seperaing any gui based code from the threads. All processing of data is done in thread and all populating of the gui tables, boxes etc down once the threads have eneded. – PhilFPH Feb 06 '19 at 20:14