如何使用Qt创build暂停/等待function?
我正在玩Qt ,我想在两个命令之间创build一个简单的停顿。 但是,似乎不让我使用Sleep(int mili);
,我找不到任何明显的等待function。
我基本上只是做一个控制台应用程序来testing一些类的代码,这些代码稍后将包含在一个合适的Qt GUI中,所以现在我不打扰整个事件驱动模型。
这个前面的问题提到使用QtTest
模块中的QtTest
qSleep()
。 为了避免QtTest
模块中的开销链接,查看该函数的源代码,您可以制作自己的副本并调用它。 它使用定义来调用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 }
我为在Qt中开发的应用程序编写了一个超级简单的延迟函数。
我build议你使用这个代码而不是睡眠函数,因为它不会让你的GUI冻结。
这里是代码:
void delay() { QTime dieTime= QTime::currentTime().addSecs(1); while (QTime::currentTime() < dieTime) QCoreApplication::processEvents(QEventLoop::AllEvents, 100); }
要延迟一个事件n秒 – 使用addSecs(n)
。
对kshark27的答案小1使其dynamic:
#include <QTime> void delay( int millisecondsToWait ) { QTime dieTime = QTime::currentTime().addMSecs( millisecondsToWait ); while( QTime::currentTime() < dieTime ) { QCoreApplication::processEvents( QEventLoop::AllEvents, 100 ); } }
从Qt5起,我们也可以使用
QThread的静态公共成员
void msleep(unsigned long msecs) void sleep(unsigned long secs) void usleep(unsigned long usecs)
我们一直在使用下面的课程 –
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旨在协调不同线程之间的互斥等待。 但是什么使得这个工作是等待方法有一个超时。 当以这种方式调用时,它的function与睡眠函数完全相同,但它使用Qt的事件循环来进行计时。 所以,没有其他事件或UI像正常的Windows睡眠function那样被阻塞。
作为奖励,我们添加了CancelSleep函数来允许程序的另一部分取消“睡眠”function。
我们喜欢的是它轻巧,可重复使用,完全独立。
QMutex: http ://doc.qt.io/archives/4.6/qmutex.html
QWaitCondition: http : //doc.qt.io/archives/4.6/qwaitcondition.html
既然你试图“testing一些类的代码”,我真的build议学习使用QTestLib 。 它提供了一个QTest命名空间和一个QtTest模块 ,其中包含许多有用的函数和对象,包括QSignalSpy ,您可以使用它来validation某些信号是否被发射。
既然你最终将整合GUI,使用QTestLib和testing没有睡觉或等待会给你一个更准确的testing – 一个更好地代表了真正的使用模式。 但是,如果你select不走那条路线,你可以使用QTestLib :: qSleep来完成你所要求的。
由于您只需在启动泵和closures泵之间暂停一下,就可以轻松使用单次计时器:
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(); }
但是如果你感兴趣的话, qSleep()
肯定会更容易在命令行上validation一些事情。
编辑 :根据评论,这是所需的使用模式。
首先,你需要编辑你的.pro文件来包含qtestlib:
CONFIG += qtestlib
其次,你需要包含必要的文件:
- 对于QTest命名空间(包括
qSleep
):#include <QTest>
- 对于
QtTest
模块中的所有项目:#include <QtTest>
。 这在function上等价于为名称空间中存在的每个项目添加一个include。
要使用标准睡眠function,请在.cpp文件中添加以下内容:
#include <unistd.h>
从Qt版本4.8开始,可以使用以下睡眠函数:
void QThread::msleep(unsigned long msecs) void QThread::sleep(unsigned long secs) void QThread::usleep(unsigned long usecs)
要使用它们,只需在.cpp文件中添加以下内容:
#include <QThread>
参考:QThread(通过Qt文档): http : //doc.qt.io/qt-4.8/qthread.html
否则,执行这些步骤…
修改项目文件如下:
CONFIG += qtestlib
请注意,在较新版本的Qt中,您将看到以下错误:
Project WARNING: CONFIG+=qtestlib is deprecated. Use QT+=testlib instead.
…所以,而是修改项目文件,如下所示:
QT += testlib
然后,在.cpp文件中,一定要添加以下内容:
#include <QtTest>
然后使用其中一个睡眠function,如下所示:
usleep(100);
类似于这里的一些答案,但也许更轻量一点
void MyClass::sleepFor(qint64 milliseconds){ qint64 timeToExitFunction = QDateTime::currentMSecsSinceEpoch()+milliseconds; while(timeToExitFunction>QDateTime::currentMSecsSinceEpoch()){ QApplication::processEvents(QEventLoop::AllEvents, 100); } }
如果你想要一个跨平台的方法,一般的模式是从QThread派生,并在派生类中创build一个函数(如果你愿意的话),它将调用QThread中的一个睡眠函数。
@ kshark27的答案由于某种原因不适用于我(因为我使用Qt 5.7),所以我最终这样做了:
while (someCondition) { // do something QApplication::processEvents(); QThread::sleep(1); // 1 second };
这是在GUI线程中完成的,显然这会在响应用户事件之前引入1秒的GUI延迟。 但是,如果你能忍受它,这个解决scheme可能是最容易实现的,甚至Qt也会在他们的Threading Basics文章中看到它(参见何时使用线程替代方法部分)。
多年来,我在尝试使QApplication :: processEvents正常工作时遇到了很多麻烦,正如一些顶级答案中所使用的。 IIRC,如果多个位置最终调用它,可能会导致一些信号不被处理( https://doc.qt.io/archives/qq/qq27-responsive-guis.html )。 我通常喜欢的select是使用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(); }