18


Hello everyone! I've found something strange on QPushButton instance. Oh, first of all, I am using..

  • windows 7
  • python 3.4
  • PyQt5

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!

coder
  • 8,346
  • 16
  • 39
  • 53
passion053
  • 473
  • 3
  • 8
  • 21

2 Answers2

33

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.

Community
  • 1
  • 1
Imanol Luengo
  • 15,366
  • 2
  • 49
  • 67
10

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.

Michał Fita
  • 1,183
  • 1
  • 7
  • 24