passion053
passion053

Reputation: 493

How to make push button immediately disabled?


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

Answers (2)

Imanol Luengo
Imanol Luengo

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

Michał Fita
Michał Fita

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

Related Questions