Reputation: 493
Hello everyone! I've found something strange on QPushButton instance. Oh, first of all, I am using..
My test code is...
# coding: utf-8
import sys, time
from PyQt5.QtWidgets import QWidget, QApplication, QPushButton
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.targetBtn = QPushButton('target', self)
self.targetBtn.move(100, 100)
self.targetBtn.clicked.connect(self.sleep5sec)
self.setGeometry(100, 100, 300, 300)
self.show()
def sleep5sec(self):
self.targetBtn.setEnabled(False)
time.sleep(5)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
What I want is.. when a user push the target button, the button immediately disabled. But in my code, target button is disabled after sleep(5).
What's wrong with my code?
Thank you for reading my question! Please help!
Upvotes: 20
Views: 68568
Reputation: 15889
As suggested in the thread I linked in the comment and @MichalF, python's sleep
completely freezes the UI, so it does not let the .setEnabled
method to be updated.
In Qt all events are managed with the UI's main thread (which is another worker) and thus, actions like .setEnabled
have no immediate effect in the UI (takes a bit to repaint it). Using time.sleep
the UI threads freeze and thus, the Qt's main worker doesn't update (repaint) de UI until the timer is ended.
A way to change it is by using PyQt5.QtCore.QTimer:
def sleep5sec(self):
self.targetBtn.setEnabled(False)
QTimer.singleShot(5000, lambda: self.targetBtn.setDisabled(False))
The above example would instantly disable targetBtn
and after 5 second it will re-enable it again.
Upvotes: 36
Reputation: 1319
Rule of thumb: DONT USE sleep()
IN GUI APPLICATION!
GUI application of almost any kind works in something called event loop
, which is single thread mechanism responding to events passed from the operating system (or windows system). If you sleep there, your event loop doesn't work.
When you connected you clicked
signal to a method that sleeps inside, the event loop doesn't have a chance to finish signal handling and refresh the image of the interface on the screen, as that happens after the signal is handled. Refreshing graphical elements is done by series of signals send internally.
Upvotes: 11