如何使用Qt创建暂停/等待功能?

Zac*_*Zac 70 c++ qt sleep wait

我正在玩Qt,我想在两个命令之间创建一个简单的暂停.但是它似乎没有让我使用Sleep(int mili);,我找不到任何明显的等待功能.

我基本上只是制作一个控制台应用程序来测试一些类代码,这些代码稍后将包含在一个合适的Qt GUI中,所以现在我不打算打破整个事件驱动的模型.

小智 130

我为Qt开发的应用程序编写了一个超级简单的延迟函数.

我建议你使用这个代码而不是睡眠功能,因为它不会让你的GUI冻结.

这是代码:

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

要将事件延迟n秒 - 请使用addSecs(n).

  • 在Qt 5.7中将它放入`while`循环时,我只是经历100%CPU负载的人吗? (6认同)
  • 如果没有挂起事件,`processEvents()`函数将立即返回,这将导致忙循环(占用100%的CPU).因此,您应该在循环中添加逻辑以等待剩余的100ms循环时间. (6认同)
  • 使用时钟时间的这种延迟功能是许多应用程序有时不能按预期工作的原因,并且没有人能够轻易地重现该问题.超时和延迟不应该使用时钟时间.如果由于第一个`currentTime()`和任何进一步的'currentTime()`调用之间的日期/时间变化而修改运行具有此代码的应用程序的机器的日期/时间,则延迟是错误的.根据日期/时间的变化,延迟要么过早,要么太晚(太晚,几分钟,几小时,几天,几个月甚至几年太晚).使用延迟/超时的时钟时间是不行的. (4认同)
  • 非常感谢你这个美丽的功能!正是我所寻找的,因为它没有暂停主事件循环. (2认同)
  • 这非常危险,因为'processEvents'基本上意味着'任何事情都可能发生'.您可能最终处理套接字通信,它可能导致Qt对象被删除 - 或者应用程序终止.所有隐藏在程序中无害的查看`delay();`声明的背后. (2认同)

Yas*_*ash 62

从Qt5开始我们也可以使用

QThread的静态公共成员

void    msleep(unsigned long msecs)
void    sleep(unsigned long secs)
void    usleep(unsigned long usecs)
Run Code Online (Sandbox Code Playgroud)

  • 这应该是公认的答案.它简单易用,不会耗尽所有CPU周期. (4认同)
  • 但它仍然会使 GUI 没有响应 (3认同)

Gra*_*amF 31

kshark27的小答案让它变得动态:

#include <QTime>

void delay( int millisecondsToWait )
{
    QTime dieTime = QTime::currentTime().addMSecs( millisecondsToWait );
    while( QTime::currentTime() < dieTime )
    {
        QCoreApplication::processEvents( QEventLoop::AllEvents, 100 );
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 见上面的评论.这可能导致在正常情况下忙碌等待100%cpu使用(空事件队列),并且在循环运行时调整更大的系统时钟问题. (2认同)

Arn*_*nce 30

先前的问题提到使用qSleep()这是在QtTest模块.为了避免QtTest模块中的开销链接,查看该函数的源代码,您可以自己创建并调用它.它使用define来调用Windows Sleep()或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
}
Run Code Online (Sandbox Code Playgroud)


pho*_*tom 9

我们一直在使用以下课程 -

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

QWaitCondition旨在协调不同线程之间的互斥等待.但是这个工作的原因是wait方法有一个超时.当以这种方式调用时,它的功能与睡眠功能完全相同,但它使用Qt的事件循环进行计时.因此,没有像正常的Windows睡眠功能那样阻止其他事件或UI.

作为奖励,我们添加了CancelSleep函数,允许程序的另一部分取消"睡眠"功能.

我们喜欢这个,它重量轻,可重复使用,完全独立.

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

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


dvn*_*0bz 7

多年来,在尝试使QApplication :: processEvents正常工作时遇到了很多麻烦,就像在一些最佳答案中所使用的那样。IIRC,如果多个位置最终调用它,则可能导致某些信号无法处理(https://doc.qt.io/archives/qq/qq27-sensitive-guis.html)。我通常的首选选择是利用QEventLoop(https://doc.qt.io/archives/qq/qq27-sensitive-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();
}
Run Code Online (Sandbox Code Playgroud)

  • 即使在今天也是很好的解决方案。这应该是公认的答案。无需挂起 GUI 即可工作,也无需 hacky sleeps() 或 processEvents()。谢谢! (2认同)

Kal*_*son 6

既然你正试图"测试一些类代码",我真的建议学习使用QTestLib.它提供了一个QTest命名空间和一个QtTest模块,其中包含许多有用的函数和对象,包括可用于验证是否发出某些信号的QSignalSpy.

由于您最终将使用完整的GUI进行集成,因此使用QTestLib并在不休眠或等待的情况下进行测试将为您提供更准确的测试 - 更好地代表真实的使用模式.但是,如果您选择不去那条路线,您可以使用QTestLib :: qSleep来执行您所要求的操作.

由于您只需要在启动泵和关闭泵之间暂停,您可以轻松使用单次计时器:

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();
}
Run Code Online (Sandbox Code Playgroud)

qSleep()如果您感兴趣的是在命令行上验证一些事情,那肯定会更容易.

编辑:根据评论,这是所需的使用模式.

首先,您需要编辑.pro文件以包含qtestlib:

CONFIG += qtestlib
Run Code Online (Sandbox Code Playgroud)

其次,您需要包含必要的文件:

  • 对于QTest命名空间(包括qSleep):#include <QTest>
  • 对于QtTest模块中的所有项目:#include <QtTest>.这在功能上等同于为命名空间中存在的每个项添加包含.


Ric*_*ski 6

要使用标准睡眠功能,请在.cpp文件中添加以下内容:

#include <unistd.h>
Run Code Online (Sandbox Code Playgroud)

从Qt版本4.8开始,可以使用以下睡眠功能:

void QThread::msleep(unsigned long msecs)
void QThread::sleep(unsigned long secs)
void QThread::usleep(unsigned long usecs)
Run Code Online (Sandbox Code Playgroud)

要使用它们,只需在.cpp文件中添加以下内容:

#include <QThread>
Run Code Online (Sandbox Code Playgroud)

参考:QThread(通过Qt文档):http: //doc.qt.io/qt-4.8/qthread.html

否则,执行以下步骤......

修改项目文件,如下所示:

CONFIG += qtestlib
Run Code Online (Sandbox Code Playgroud)

请注意,在较新版本的Qt中,您将收到以下错误:

Project WARNING: CONFIG+=qtestlib is deprecated. Use QT+=testlib instead.
Run Code Online (Sandbox Code Playgroud)

...所以,修改项目文件,如下所示:

QT += testlib
Run Code Online (Sandbox Code Playgroud)

然后,在.cpp文件中,请务必添加以下内容:

#include <QtTest>
Run Code Online (Sandbox Code Playgroud)

然后使用其中一个睡眠功能:

usleep(100);
Run Code Online (Sandbox Code Playgroud)

  • 这些功能受到保护! (2认同)