90

I'm playing around with Qt, and I want to create a simple pause between two commands. However it won't seem to let me use Sleep(int mili);, and I can't find any obvious wait functions.

I am basically just making a console application to test some class code which will later be included in a proper Qt GUI, so for now I'm not bothered about breaking the whole event-driven model.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Zac
  • 2,229
  • 9
  • 33
  • 41
  • What exactly are you testing? What does adding a `wait()` or `sleep()` accomplish? – Kaleb Pederson Sep 20 '10 at 15:39
  • 1
    I am creating a class to drive a peristatic pump using RS232 serial commands. I have created a GUI in QT but in the mean time I am just testing the functions I have created from a main() function within the console. Thus I want the class to be compiled by QT but at the same time I want to mypump.startpump(); sleep(1000); mypump.stoppump(); for instance. just to test it works. – Zac Sep 20 '10 at 15:56
  • Despite compiling with QT I am using CONFIG += console to run and output debugging strings to the console. – Zac Sep 20 '10 at 15:56
  • 7
    `QObject().thread()->usleep(1000*1000*seconds);` will sleep for `seconds` seconds :) – mlvljr Jul 23 '14 at 22:30
  • I wish you could up vote comments. mlvijr's answer worked perfect. You should make an answer. – bandito40 Apr 08 '19 at 02:25

13 Answers13

152

I wrote a super simple delay function for an application I developed in Qt.

I would advise you to use this code rather than the sleep function as it won't let your GUI freeze.

Here is the code:

void delay()
{
    QTime dieTime= QTime::currentTime().addSecs(1);
    while (QTime::currentTime() < dieTime)
        QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}

To delay an event by n seconds - use addSecs(n).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Kartik Sharma
  • 1,713
  • 2
  • 10
  • 5
  • 2
    Thank you so much for this beautiful function! Exactly what I was looking for as it does not suspend the main event loop. – Marc Apr 25 '14 at 07:58
  • This is one of those code nuggets that every now and then you come across and just think "Why didn't I think of that". Good job. – GPPK Dec 19 '15 at 20:44
  • 8
    Am I only the one who experiences 100% CPU load when putting this in `while` loop in Qt 5.7? – Neurotransmitter Aug 30 '16 at 23:04
  • 4
    Such delay functions using the clock time are the cause why many applications sometimes do not work as expected and nobody can easily reproduce the problem. Timeouts and delays should never use the clock time. The delay is wrong if date/time of machine running the application with this code is modified due to a date/time change between first `currentTime()` and any further `currentTime()` calls. Depending on date/time change the delay either expires too early or much too late (seconds, minutes, hours, days, months or even years too late). Usage of clock time for delays/timeouts is a no go. – Mofi Mar 31 '17 at 11:32
  • 9
    The `processEvents()` function will return immediately if there are no pending events, which results in a busy loop (taking 100% of the CPU). Hence, you should add logic in the loop to wait for the remainder of the 100ms loop time left. – DavidJ Apr 12 '17 at 04:23
  • 5
    This is extremely dangerous since 'processEvents' basically means 'anything can happen'. You may end up processing socket communication, it may cause Qt objects to get deleted - or the application to terminate. All that hidden behind a harmless looking `delay();` statement in your program. – Frerich Raabe Feb 15 '18 at 15:13
  • 1
    **This is objectively awful.** Just call the existing static public `QThread.msleep()`, `QThread.usleep()`, or `QThread.sleep()` methods – as detailed by [what *should* have been the accepted answer](https://stackoverflow.com/a/29150102/2809027). – Cecil Curry Aug 04 '18 at 02:18
  • 1
    Do not use this. Other than the busy-waiting issue, QTime wraps around at midnight, so if this gets called shortly before then and misses its window, this code won't terminate. One way to get around this would be to use QElapsedTimer (since Qt4.7), although I'd personally use QEventLoop (see [dvntehn00bz's answer](https://stackoverflow.com/a/43003223/1796978)) instead. – mreithub Dec 10 '18 at 14:35
107

From Qt5 onwards we can also use

Static Public Members of QThread

void    msleep(unsigned long msecs)
void    sleep(unsigned long secs)
void    usleep(unsigned long usecs)
Ross Rogers
  • 23,523
  • 27
  • 108
  • 164
Yash
  • 6,644
  • 4
  • 36
  • 26
38

This previous question mentions using qSleep() which is in the QtTest module. To avoid the overhead linking in the QtTest module, looking at the source for that function you could just make your own copy and call it. It uses defines to call either Windows Sleep() or Linux nanosleep().

#ifdef Q_OS_WIN
#include <windows.h> // for Sleep
#endif
void QTest::qSleep(int ms)
{
    QTEST_ASSERT(ms > 0);

#ifdef Q_OS_WIN
    Sleep(uint(ms));
#else
    struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
    nanosleep(&ts, NULL);
#endif
}
Community
  • 1
  • 1
Arnold Spence
  • 21,942
  • 7
  • 74
  • 67
  • Thanks, the including windows.h enables the use of Sleep(); This will do for now as I understand I will not be using this code in the final program because it breaks the event driven model but for now this enables me to test the program as is. – Zac Sep 20 '10 at 16:10
  • Where did you find the source? – Tomáš Zato Aug 02 '16 at 21:47
  • It's now six years later and a few changed hands but you can find the open source version of Qt at https://www.qt.io/download-open-source. There are links there that will lead to the source code. I have no idea if the code above still exists. – Arnold Spence Aug 03 '16 at 04:30
37

Small +1 to kshark27's answer to make it dynamic:

#include <QTime>

void delay( int millisecondsToWait )
{
    QTime dieTime = QTime::currentTime().addMSecs( millisecondsToWait );
    while( QTime::currentTime() < dieTime )
    {
        QCoreApplication::processEvents( QEventLoop::AllEvents, 100 );
    }
}
Community
  • 1
  • 1
GraehamF
  • 1,971
  • 24
  • 24
  • plus one, small note: I guess you `#include ` also ´#include ` – Jack Sep 17 '15 at 22:01
  • 4
    See comments above. This can cause busy-wait 100% cpu usage under normal circumstances (empty event queue) and bigger issues of the system clock is adjusted when the loop is running. – DavidJ Apr 12 '17 at 04:26
  • #include – nvd Jul 12 '17 at 11:31
21

I've had a lot of trouble over the years trying to get QApplication::processEvents to work, as is used in some of the top answers. IIRC, if multiple locations end up calling it, it can end up causing some signals to not get processed (https://doc.qt.io/archives/qq/qq27-responsive-guis.html). My usual preferred option is to utilize a QEventLoop (https://doc.qt.io/archives/qq/qq27-responsive-guis.html#waitinginalocaleventloop).

inline void delay(int millisecondsWait)
{
    QEventLoop loop;
    QTimer t;
    t.connect(&t, &QTimer::timeout, &loop, &QEventLoop::quit);
    t.start(millisecondsWait);
    loop.exec();
}
dvntehn00bz
  • 637
  • 6
  • 12
  • 2
    Great solution, even today. This should be the accepted answer. Works without hanging up the GUI and without hacky sleeps() or processEvents(). Thanks! – Jack Aug 03 '20 at 14:31
  • This SHOULD be the accepted answer. It does not spike CPU, uses event system to expire timer, and no loops. – TSG Nov 17 '21 at 17:05
9

We've been using the below class -

class SleepSimulator{
     QMutex localMutex;
     QWaitCondition sleepSimulator;
public:
    SleepSimulator::SleepSimulator()
    {
        localMutex.lock();
    }
    void sleep(unsigned long sleepMS)
    {
        sleepSimulator.wait(&localMutex, sleepMS);
    }
    void CancelSleep()
    {
        sleepSimulator.wakeAll();
    }
};

QWaitCondition is designed to coordinate mutex waiting between different threads. But what makes this work is the wait method has a timeout on it. When called this way, it functions exactly like a sleep function, but it uses Qt's event loop for the timing. So, no other events or the UI are blocked like normal windows sleep function does.

As a bonus, we added the CancelSleep function to allows another part of the program to cancel the "sleep" function.

What we liked about this is that it lightweight, reusable and is completely self contained.

QMutex: http://doc.qt.io/archives/4.6/qmutex.html

QWaitCondition: http://doc.qt.io/archives/4.6/qwaitcondition.html

Christophe Weis
  • 2,518
  • 4
  • 28
  • 32
photo_tom
  • 7,292
  • 14
  • 68
  • 116
  • At least the [current implementation in qt5](https://github.com/qt/qtbase/blob/8b91c6831546f884437122ce243b8a08c328a13c/src/corelib/thread/qwaitcondition_unix.cpp#L205) does not seem to communicate with event loop at all, so from the pov of "processing events" this is "interruptable sleep". – joonas Oct 10 '19 at 10:12
7

To use the standard sleep function add the following in your .cpp file:

#include <unistd.h>

As of Qt version 4.8, the following sleep functions are available:

void QThread::msleep(unsigned long msecs)
void QThread::sleep(unsigned long secs)
void QThread::usleep(unsigned long usecs)

To use them, simply add the following in your .cpp file:

#include <QThread>

Reference: QThread (via Qt documentation): http://doc.qt.io/qt-4.8/qthread.html

Otherwise, perform these steps...

Modify the project file as follows:

CONFIG += qtestlib

Note that in newer versions of Qt you will get the following error:

Project WARNING: CONFIG+=qtestlib is deprecated. Use QT+=testlib instead.

... so, instead modify the project file as follows:

QT += testlib

Then, in your .cpp file, be sure to add the following:

#include <QtTest>

And then use one of the sleep functions like so:

usleep(100);
6

Since you're trying to "test some class code," I'd really recommend learning to use QTestLib. It provides a QTest namespace and a QtTest module that contain a number of useful functions and objects, including QSignalSpy that you can use to verify that certain signals are emitted.

Since you will eventually be integrating with a full GUI, using QTestLib and testing without sleeping or waiting will give you a more accurate test -- one that better represents the true usage patterns. But, should you choose not to go that route, you could use QTestLib::qSleep to do what you've requested.

Since you just need a pause between starting your pump and shutting it down, you could easily use a single shot timer:

class PumpTest: public QObject {
    Q_OBJECT
    Pump &pump;
public:
    PumpTest(Pump &pump):pump(pump) {};
public slots:
    void start() { pump.startpump(); }
    void stop() { pump.stoppump(); }
    void stopAndShutdown() {
        stop();
        QCoreApplication::exit(0);
    }
    void test() {
        start();
        QTimer::singleShot(1000, this, SLOT(stopAndShutdown));
    }
};

int main(int argc, char* argv[]) {
    QCoreApplication app(argc, argv);
    Pump p;
    PumpTest t(p);
    t.test();
    return app.exec();
}

But qSleep() would definitely be easier if all you're interested in is verifying a couple of things on the command line.

EDIT: Based on the comment, here's the required usage patterns.

First, you need to edit your .pro file to include qtestlib:

CONFIG += qtestlib

Second, you need to include the necessary files:

  • For the QTest namespace (which includes qSleep): #include <QTest>
  • For all the items in the QtTest module: #include <QtTest>. This is functionally equivalent to adding an include for each item that exists within the namespace.
Christophe Weis
  • 2,518
  • 4
  • 28
  • 32
Kaleb Pederson
  • 45,767
  • 19
  • 102
  • 147
4

@kshark27's answer didn't work for me for some reason (because I use Qt 5.7?) so I ended up doing this:

while (someCondition) {

   // do something

   QApplication::processEvents();
   QThread::sleep(1); // 1 second

};

If this is done in the GUI thread, it obviously introduces a 1 second GUI lag before responding to user events. But if you can live with it, this solution is probably an easiest to implement and even Qt endorses it in their Threading Basics article (see When to Use Alternatives to Threads section).

Neurotransmitter
  • 6,289
  • 2
  • 51
  • 38
3

we can use following method QT_Delay:

QTimer::singleShot(2000,this,SLOT(print_lcd()));

This will wait for 2 seconds before calling print_lcd().

razdi
  • 1,388
  • 15
  • 21
3

This work fine with Qt5:

void wait( int ms ) {
   QElapsedTimer timer;
   timer.start();

   while ( timer.elapsed() < ms )
       QCoreApplication::processEvents();
}
Calanor
  • 41
  • 3
2

Similar to some answers here, but maybe a little more lightweight

void MyClass::sleepFor(qint64 milliseconds){
    qint64 timeToExitFunction = QDateTime::currentMSecsSinceEpoch()+milliseconds;
    while(timeToExitFunction>QDateTime::currentMSecsSinceEpoch()){
        QApplication::processEvents(QEventLoop::AllEvents, 100);
    }
}
hytromo
  • 1,501
  • 2
  • 27
  • 57
1

If you want a cross-platform method of doing this, the general pattern is to derive from QThread and create a function (static, if you'd like) in your derived class that will call one of the sleep functions in QThread.

San Jacinto
  • 8,774
  • 5
  • 43
  • 58
  • or even better -- see the last comment under the question (as of today), thanks for inspiring that :) – mlvljr Jul 23 '14 at 22:33