22

I can't use time.sleep in my pyqt application because that freezes the GUI thread, so the GUI will be completely frozen during this time.I have been looking for a way to handle this.

I tried to use QTimer, but it seemed like they need to be linked to another function? Like wait ten seconds then run some function. Is there a way to just have it wait then continue with the current function?

def num(self):
    for i in range(1,999):
        print i
        #Add some sleep here

def testSleep(self):
    QtCore.QTimer.singleShot(2000, self.num)
ti7
  • 16,375
  • 6
  • 40
  • 68
PAR
  • 624
  • 1
  • 5
  • 16
  • split current function into two functions and use `QTimer` – furas Jan 09 '17 at 10:06
  • the function is getting executed again and again – PAR Jan 09 '17 at 10:34
  • 2
    see doc [QTimer](http://pyqt.sourceforge.net/Docs/PyQt4/qtimer.html) - it has method `singleShot()` – furas Jan 09 '17 at 10:50
  • better add small, working example in question - it will be more readable and everyone can run it and see your problem. – furas Jan 09 '17 at 10:54
  • as for me you should use `QTimer` instead of `for-loop` with something like `if run_again: singleShot(2000, self.num)` – furas Jan 09 '17 at 10:56
  • Are you asking how to keep the GUI responsive if num() takes several seconds to run? I don't think either answer addresses this. – Oliver Jan 09 '17 at 21:31
  • What is status of this, several answers and you haven't commented if any helped – Oliver Jan 26 '17 at 00:55
  • @Schollii I have answered it below. I tried to implement the sleep time making the GUI responsive using QtTest. – PAR Jan 27 '17 at 04:11
  • I believe that I understand what @PAR wants because I want exactly the same thing. In a coroutine environment it would be analogous to `await async_sleep()` so that we can stay in the same function context after the sleep is complete. Hopefully this clarification will get an eye on it who knows what `QTest.qWait()` is doing. – paulluap Jan 27 '18 at 19:02

5 Answers5

29

Actually i was looking for time.sleep alternative to use in pyqt without using any thread concepts.

And the solution i figured out is:

from PyQt4 import QtTest

QtTest.QTest.qWait(msecs)

This works similar to time.sleep making GUI responsive.

Thankyou for your answers.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
PAR
  • 624
  • 1
  • 5
  • 16
  • Do you need this for a test suite or an application? – Oliver Jan 27 '17 at 15:57
  • Its for application. – PAR Jan 30 '17 at 05:41
  • 3
    Then using QtTest is not appropriate, it is for unit tests. Plus, if it can be done by QtTset, it can be done directly in PyQt. If you need to wait some time (before trying something) without blocking the GUI you use `QTimer.singleShot()`. Your answer implies that none of the 3 other answers by advanced PyQt users were adequate, this means you're question was not clearly stated. You should either clarify it or, if you can't do that, remove it. – Oliver Jan 30 '17 at 13:26
  • 8
    This solution worked perfectly for me, no matter if it's appropriate to use or not. I just needed a simple sleep, nothing more complicated. If that is missing from PyQt (other than for tests) then I rather use that than implement anything which is more complicated than necessary. – m5seppal Aug 15 '17 at 07:48
  • Worked for me using PyQt5. – Luan Souza Aug 17 '21 at 17:25
6

Maybe it could be done better but you can always use singleShot to run function with delay, and lambda to run function with argument.

import sys
from PyQt4 import QtGui, QtCore

#def num(self, i):
def num(i):
    print i
    i += 1
    if i < 999:
        # run again after 2000ms with argument
        QtCore.QTimer.singleShot(2000, lambda:num(i))
        #QtCore.QTimer.singleShot(2000, lambda:self.num(i))

app = QtGui.QApplication(sys.argv)

# run first time with start argument
num(1)
#QtCore.QTimer.singleShot(2000, lambda:num(1))

sys.exit(app.exec_())
furas
  • 134,197
  • 12
  • 106
  • 148
3

Another option would be to process Qt events while waiting:

def num():
    for i in range(1, 999):
        print(i)
        # Sleep five seconds in total
        for _ in range(5 * 10):
            # Process events between short sleep periods
            QtWidgets.QApplication.processEvents()
            time.sleep(0.1)
ababak
  • 1,685
  • 1
  • 11
  • 23
2

You cannot use time.sleep in the pyqt main event loop as it would stop the GUI event loop from responding.

A solution in pyqt could look like this, using QTimer

import sys
from PyQt4 import QtGui, QtCore

application = QtGui.QApplication(sys.argv)

i=0
timer = QtCore.QTimer()

def num():
    global i, timer
    if i <999:
        print ( i )
        i += 1
    else:
        timer.stop()

timer.timeout.connect(num)
timer.start(2000)

sys.exit(application.exec_())
ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
2

I believe you are asking how to keep the GUI responsive if num() takes several seconds to run? You have two options:

  • if num() consists of many small chunks of "work", you can call application.processEvents() between the chunks, this will allow the GUI to respond to events. An easy situation to deal with is when most of the num() time is spent in a loop, then at the start or end of each iteration, call application.processEvents(). In your real application, if you don't have access to application, import qApp from PyQt4.
  • the better approach is to execute num() in a separate thread. There are many examples of this on SO (like this one). One way of doing that is

    • instantiate a QThread,
    • define a class (say NumberCruncher) that derives from QObject and defines num(self) and defines a signal 'done' emitted by num() before returning
    • call numberCruncher.moveToThread(thread)
    • connect the thread started signal to num
    • start the thread
Community
  • 1
  • 1
Oliver
  • 27,510
  • 9
  • 72
  • 103
  • Actually num() func i described here internally imports multiple scripts, so in each different script based on the response an appropriate sleep time was necessary to add. This was making the GUI hung. Even i cant implement thread concept here as it involves many code changes. So i was trying for sleep alternative in Pyqt. – PAR Jan 27 '17 at 04:14