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



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



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

4314   11  

11 ответов:

этой предыдущий вопрос упоминает, используя qSleep() который находится в QtTest модуль. Чтобы избежать накладных расходов, связанных в QtTest модуль, глядя на источник для этой функции, вы можете просто сделать свою собственную копию и вызвать ее. Он использует определяет для вызова окна 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 );
    }
}

мы использовали класс ниже -

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

начиная с версии 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>

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

usleep(100);

так как вы пытаетесь "проверить некоторый код класса", я бы действительно рекомендовал научиться использовать QTestLib. Он обеспечивает пространство имен это связано с тем и модуль 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() определенно было бы проще, если бы все, что вас интересует, это проверка нескольких вещей в команде линия.

EDIT: на основе комментария, вот необходимые шаблоны использования.

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

CONFIG += qtestlib

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

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

У меня было много проблем на протяжении многих лет, пытаясь заставить QApplication::processEvents работать, как это используется в некоторых из лучших ответов. IIRC, если несколько мест в конечном итоге вызывают его, это может привести к тому, что некоторые сигналы не будут обработаны (https://doc.qt.io/archives/qq/qq27-responsive-guis.html). Мой обычный предпочтительный вариант-использовать 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();
}

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

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

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

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

while (someCondition) {

   // do something

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

};

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

Comments

    Ничего не найдено.