Reputation: 10476
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:
It does, however, correctly close after 2 seconds.
However, if I change a.show()
to a.exec()
, then I get the following:
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
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