ignoring_gravity
ignoring_gravity

Reputation: 10476

Making a window which is displayed until code finishes executing

EDIT: The purpose of the timer was to simulate other code which takes a long time to execute. Imagine that, instead of time.sleep(2) , there is a function which takes a long time to execute.

I have written the following test code:

from PyQt5.QtWidgets import (QPushButton, QApplication, QMainWindow, QDialog,
                             QVBoxLayout, QLabel)
import sys
import time

class MyWarnings(QDialog):
    ''' Generic popup window with text.'''

    def __init__(self):
        super(MyWarnings, self).__init__()
        widget = QLabel('wait')
        layout = QVBoxLayout()
        layout.addWidget(widget)
        self.setLayout(layout)

class Window(QMainWindow):

    def __init__(self):

        QMainWindow.__init__(self)
        self.widget = QPushButton('push me')
        self.widget.pressed.connect(self.push_me)
        self.setCentralWidget(self.widget)

    def push_me(self):
        a = MyWarnings()
        a.show()
        time.sleep(2)

        self.widget.setText('done!')

app = QApplication(sys.argv)
window = Window()
window.show()
app.exec_()

There is a button ('push me'), and if the user presses it, then after 2 seconds it reads 'done!'.

After the user pushes the button, I would like a window to pop up saying 'please wait', which should close automatically when those two seconds are up (i.e. when the rest of the code has finished executing)

If I run the above code, then a window does indeed pop up, but nothing is displayed on it:

enter image description here

It does, however, correctly close after 2 seconds.

However, if I change a.show() to a.exec(), then I get the following:

enter image description here

So it displays the correct text, but doesn't close (and, in fact, interrupts execution for the rest of the file).

How can I get the window to display 'wait' while the rest of the code executes, without halting it?

Upvotes: 1

Views: 694

Answers (1)

eyllanesc
eyllanesc

Reputation: 243937

Blocking tasks should not be used because the GUI runs inside an event loop that allows you to check others such as the mouse, the keyboard, etc., and the redraw, if you do not, it will not be able to do it and therefore it will not redraw the widget with the new text.

The blocking tasks should be replaced as much as possible by synchronous tasks, or else it can be executed in another thread and notified to the main thread through signals.

import sys

import time
import threading

from PyQt5.QtWidgets import (QPushButton, QApplication, QMainWindow, QDialog, QVBoxLayout, QLabel)
from PyQt5.QtCore import QObject, pyqtSignal

class Helper(QObject):
    finished = pyqtSignal()

def some_task(helper):
    time.sleep(2)
    helper.finished.emit()

class MyWarnings(QDialog):
    def __init__(self):
        super(MyWarnings, self).__init__()
        widget = QLabel('wait')
        layout = QVBoxLayout()
        layout.addWidget(widget)
        self.setLayout(layout)

class Window(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        self.widget = QPushButton('push me')
        self.widget.pressed.connect(self.push_me)
        self.setCentralWidget(self.widget)

    def push_me(self):
        self.a = MyWarnings()
        self.a.show()
        self.helper = Helper()
        self.helper.finished.connect(lambda: self.widget.setText('done!'))
        self.helper.finished.connect(self.a.close)
        threading.Thread(target=some_task, args=(self.helper, )).start()


app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())

Upvotes: 1

Related Questions