web-dev-qa-db-ja.com

Qtを使用して一時停止/待機機能を作成するにはどうすればよいですか?

Qt で遊んでいるので、2つのコマンドの間に単純な一時停止を作成したい。しかし、Sleep(int mili);を使用できるようには思われないため、明らかな待機関数は見つかりません。

基本的に、後で適切なQt GUIに含まれるクラスコードをテストするためのコンソールアプリケーションを作成しているだけなので、今のところ、イベント駆動型モデル全体を壊すことを気にしません。

65
Zac

この 前の質問 は、QtTestモジュールにあるqSleep()を使用することに言及しています。 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
}
29
Arnold Spence

Qtで開発したアプリケーション用に、非常に単純な遅延関数を作成しました。

GUIがフリーズしないため、スリープ関数ではなくこのコードを使用することをお勧めします。

コードは次のとおりです。

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

イベントをn秒遅延させるには、addSecs(n)を使用します。

125
Kartik Sharma

Qt5以降では、

QThreadの静的パブリックメンバー

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

動的にするための kshark27 の回答への+1:

#include <QTime>

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

以下のクラスを使用しています-

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のイベントループを使用します。したがって、他のイベントやUIは、通常のWindowsスリープ機能のようにブロックされません。

ボーナスとして、CancelSleep関数を追加して、プログラムの別の部分で「スリープ」機能をキャンセルできるようにしました。

この点で気に入ったのは、軽量で再利用可能で、完全に自己完結型であるということです。

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

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

9
photo_tom

標準sleep関数を使用するには、次を.cppファイルに追加します。

#include <unistd.h>

Qtバージョン4.8では、次のsleep関数が利用可能です:

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);
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();
}

ただし、コマンドラインでいくつかのことを確認するだけであれば、qSleep()の方が間違いなく簡単です。

EDIT:コメントに基づいて、必要な使用パターンを以下に示します。

まず、.proファイルを編集してqtestlibを含める必要があります。

CONFIG += qtestlib

次に、必要なファイルを含める必要があります。

  • QTest名前空間(qSleepを含む)の場合:#include <QTest>
  • QtTestモジュールのすべてのアイテム:#include <QtTest>。これは、名前空間内に存在する各アイテムにインクルードを追加することと機能的に同等です。
6
Kaleb Pederson

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();
}
4
dvntehn00bz

ここのいくつかの答えに似ていますが、もう少し軽量かもしれません

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

次のメソッドQT_Delayを使用できます。

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

これは、print_lcd()を呼び出す前に2秒間待機します。

1
user11514364

@ kshark27 の答えは、何らかの理由で(Qt 5.7を使用しているので?)私にはうまくいきませんでした。

while (someCondition) {

   // do something

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

};

これがGUIスレッドで行われる場合、ユーザーイベントに応答する前に1秒のGUIラグが明らかに導入されます。しかし、あなたがそれと一緒に生きることができるなら、このソリューションはおそらく実装が最も簡単であり、Qtでさえ Threading Basics の記事で推奨しています(を参照してくださいセクション)。

1

クロスプラットフォームでこれを行う方法が必要な場合、一般的なパターンはQThreadから派生し、派生クラスでQThreadのスリープ関数の1つを呼び出す関数(必要に応じて静的)を作成します。

1
San Jacinto