Как мне создать функцию паузы / ожидания, используя Qt?

Я играю с Qt и хочу создать простую паузу между двумя командами. Тем не менее, это не позволит мне использовать Sleep(int mili);и я не могу найти никаких очевидных функций ожидания.

По сути, я просто создаю консольное приложение для тестирования некоторого кода класса, который позже будет включен в надлежащий графический интерфейс Qt, поэтому сейчас я не беспокоюсь о нарушении всей модели, управляемой событиями.

13 ответов

Решение

Этот предыдущий вопрос упоминает использование qSleep() который находится в QtTest модуль. Чтобы избежать накладных расходов в 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.

Я бы посоветовал вам использовать этот код, а не функцию сна, поскольку он не позволит вашему графическому интерфейсу зависнуть.

Вот код:

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

Чтобы отложить событие на n секунд - используйте addSecs(n),

Начиная с Qt5 мы также можем использовать

Статические открытые члены QThread

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

Маленькое +1 к kshark27, чтобы сделать его динамичным:

#include <QTime>

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

У меня было много проблем за эти годы, пытаясь заставить работать QApplication::processEvents, как это используется в некоторых из лучших ответов. IIRC, если несколько мест в конечном итоге вызывают его, это может привести к тому, что некоторые сигналы не будут обработаны ( https://doc.qt.io/archives/qq/qq27-responsive-guis.html). Обычно я предпочитаю использовать QEventLoop ( https://doc.qt.io/archives/qq/qq27-responsive-guis.html).

inline void delay(int millisecondsWait)
{
    QEventLoop loop;
    QTimer t;
    t.connect(&t, &QTimer::timeout, &loop, &QEventLoop::quit);
    t.start(millisecondsWait);
    loop.exec();
}

Мы использовали следующий класс -

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 предназначен для координации ожидания мьютекса между различными потоками. Но что делает эту работу, так это то, что у метода wait есть тайм-аут. Когда вызывается таким образом, он функционирует точно так же, как функция сна, но он использует цикл событий Qt для синхронизации. Таким образом, никакие другие события или пользовательский интерфейс не блокируются, как это делает обычная функция сна Windows.

В качестве бонуса мы добавили функцию CancelSleep, чтобы другая часть программы могла отменить функцию "сна".

Что нам понравилось в этом, так это то, что он легкий, многоразовый и полностью автономен.

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

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

Чтобы использовать стандартную функцию сна, добавьте в ваш файл.cpp следующее:

#include <unistd.h>

Начиная с версии 4.8 Qt доступны следующие спящие функции:

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>

А затем используйте одну из функций сна следующим образом:

usleep(100);

Поскольку вы пытаетесь "протестировать некоторый код класса", я действительно рекомендую научиться использовать QTestLib. Он предоставляет пространство имен QTest и модуль QtTest, который содержит ряд полезных функций и объектов, включая QSignalSpy, который можно использовать для проверки того, что определенные сигналы испускаются.

Поскольку в конечном итоге вы будете интегрироваться с полным графическим интерфейсом, использование 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();
}

Но qSleep() было бы определенно проще, если бы все, что вас интересует, это проверка нескольких вещей в командной строке.

РЕДАКТИРОВАТЬ: на основе комментария, вот необходимые шаблоны использования.

Во-первых, вам нужно отредактировать ваш.pro-файл, включив в него qtestlib:

CONFIG += qtestlib

Во-вторых, вам необходимо включить необходимые файлы:

  • Для пространства имен QTest (которое включает в себя qSleep): #include <QTest>
  • Для всех предметов в QtTest модуль: #include <QtTest>, Это функционально эквивалентно добавлению включения для каждого элемента, который существует в пространстве имен.

kshark27 у меня почему-то не сработал (потому что я использую Qt 5.7?), поэтому я закончил тем, что сделал это:

while (someCondition) {

   // do something

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

};

Если это делается в потоке графического интерфейса, он, очевидно, вводит задержку в 1 секунду перед тем, как реагировать на пользовательские события. Но если вы можете с этим смириться, это решение, вероятно, проще всего реализовать, и даже Qt одобряет его в своей статье " Основы потоков" (см. Раздел " Когда использовать альтернативы потокам ").

Мы можем использовать следующий метод QT_Delay:

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

Это будет ждать 2 секунды, прежде чем позвонить print_lcd(),

Это отлично работает с Qt5:

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

   while ( timer.elapsed() < ms )
       QCoreApplication::processEvents();
}

Похоже на некоторые ответы здесь, но, возможно, немного более легкий

void MyClass::sleepFor(qint64 milliseconds){
    qint64 timeToExitFunction = QDateTime::currentMSecsSinceEpoch()+milliseconds;
    while(timeToExitFunction>QDateTime::currentMSecsSinceEpoch()){
        QApplication::processEvents(QEventLoop::AllEvents, 100);
    }
}

Если вам нужен кросс-платформенный метод для этого, общий шаблон - это наследование от QThread и создание функции (статической, если хотите) в вашем производном классе, которая будет вызывать одну из спящих функций в QThread.

Другие вопросы по тегам