Qtで高精度な時間計測!QElapsedTimer::hasExpired()の使い方と具体例

2025-05-27

bool QElapsedTimer::hasExpired(qint64 timeout) const とは

QElapsedTimer クラスは、時間の経過を計測するためのクラスです。特に、高精度な時間計測が必要な場合や、特定の時間内にある処理を完了させたい場合などに利用されます。

hasExpired() メソッドは、この QElapsedTimer オブジェクトが指定されたタイムアウト時間(timeout)を経過したかどうかをチェックするための便利な関数です。

  • const修飾子
    このメソッドはconst修飾子が付いているため、QElapsedTimerオブジェクトの状態を変更しません。
  • 引数
    qint64 timeout。これは、経過をチェックしたい時間(ミリ秒単位)です。
  • 戻り値
    bool型。
    • true: QElapsedTimer が開始されてから、引数で指定されたtimeout(ミリ秒単位)以上の時間が経過した場合。
    • false: QElapsedTimer が開始されてから、まだtimeoutで指定された時間が経過していない場合。

使い方

通常、QElapsedTimerオブジェクトをstart()メソッドで開始し、その後ループ処理などでhasExpired()を呼び出し、特定の時間が経過したかどうかを判断します。


#include <QElapsedTimer>
#include <QDebug>
#include <QThread> // QThread::msleep のために必要

void someOperation() {
    qDebug() << "Some operation is running...";
    // ここで何か時間のかかる処理を行う
    QThread::msleep(50); // 50ミリ秒待機
}

int main() {
    QElapsedTimer timer;
    timer.start(); // タイマーを開始

    qint64 timeoutMs = 1000; // 1秒 (1000ミリ秒) のタイムアウトを設定

    qDebug() << "タイマー開始。1秒経過するまで処理を続けます。";

    while (!timer.hasExpired(timeoutMs)) {
        // タイムアウトしていない間は処理を続ける
        someOperation();
    }

    qDebug() << "1秒が経過しました。処理を停止します。";
    qDebug() << "経過時間: " << timer.elapsed() << "ミリ秒";

    return 0;
}
  1. QElapsedTimer timer; でタイマーオブジェクトを作成します。
  2. timer.start(); でタイマーをスタートさせます。この時点から時間の計測が始まります。
  3. qint64 timeoutMs = 1000; でタイムアウト時間を1000ミリ秒(1秒)に設定します。
  4. while (!timer.hasExpired(timeoutMs)) ループでは、timer.hasExpired(timeoutMs)falseである限り(つまり、まだ1秒が経過していない限り)ループが実行されます。
  5. someOperation() は、このループ内で実行される擬似的な処理です。
  6. 1秒が経過すると、timer.hasExpired(timeoutMs)trueを返し、!演算子によって条件がfalseとなり、ループが終了します。
  7. 最後に、実際に経過した時間をtimer.elapsed()で取得し、表示しています。

hasExpired() の利点

  • 用途
    • ゲームのフレームレート制御
    • ネットワーク通信のタイムアウト処理
    • 時間制限のあるユーザー入力の待機
    • 特定の処理が一定時間内に完了したかのチェック
  • タイマーの有効性チェック
    hasExpired() は、タイマーが有効(つまり、start()が呼び出された)であるかどうかも内部的にチェックします。もしタイマーが開始されていない場合、常にtrueを返します。
  • 簡潔なコード
    指定した時間に対する経過チェックを簡潔に記述できます。
  • hasExpired() は、elapsed() メソッドの結果に基づいて計算されます。elapsed() は、タイマーが開始されてからのミリ秒数を返します。
  • QElapsedTimer は、システムクロックに依存しない、非常に正確な時間計測を提供しますが、システム全体の負荷によっては、厳密なリアルタイム性を保証するものではありません。


QElapsedTimerは、高精度な時間計測に非常に便利なツールですが、誤った使い方をすると予期しない動作を引き起こすことがあります。

start() または restart() を呼び忘れている

問題
QElapsedTimerオブジェクトを初期化しても、start()またはrestart()を呼び出さずにhasExpired()を呼び出すと、常にtrueを返したり、予期せぬ結果になったりすることがあります。これは、タイマーが「無効な状態」であるためです。

理由
hasExpired()は、タイマーが開始された時点からの経過時間をチェックします。タイマーが開始されていない場合、計測の基準点がないため、意図したように機能しません。Qtのドキュメントには、「無効なQElapsedTimerに対してこの関数を呼び出すと未定義の動作になる」と記載されています。

解決策
必ずhasExpired()を呼び出す前に、QElapsedTimerオブジェクトに対してstart()またはrestart()を呼び出してください。

QElapsedTimer timer;
// timer.start(); // これを忘れると問題が発生する

// if (timer.hasExpired(1000)) { // 常にtrueを返すか、未定義の動作
//     qDebug() << "エラー: タイマーが開始されていません!";
// }

timer.start(); // 正しくタイマーを開始する
if (timer.hasExpired(1000)) {
    qDebug() << "1秒経過しました (またはすぐに経過しました)。";
}

timeout値が適切でない(小さすぎる、大きすぎる)

問題
timeout引数に非常に小さい値(例: 0ミリ秒や負の値)を指定すると、hasExpired()はすぐにtrueを返します。逆に、非常に大きな値を指定すると、プログラムが無限ループに陥る可能性があります。

理由
hasExpired()は、単にelapsed()timeout値以上になったかどうかをチェックします。timeoutが0の場合、elapsed()は常に0以上なので、すぐに期限切れと判断されます。非常に大きなtimeoutは、実際の経過時間がその値に達するまでプログラムを待機させることになります。

解決策

  • 長時間のタイムアウトを設定する場合、その時間内に他の重要な処理がブロックされないように、非同期処理(例: QTimer、スレッド)の利用も検討してください。
  • 非常に短い時間(数ミリ秒以下)の精度が必要な場合は、OSやハードウェアのクロック精度に依存するため、QElapsedTimerが常に期待通りに動作するとは限りません。
  • timeoutの値は、処理の要件に合わせて適切に設定してください。

イベントループをブロックしている

問題
GUIアプリケーションで、while (!timer.hasExpired(timeout)) のようなループ内で重い処理を実行したり、QApplication::processEvents() を呼び出さなかったりすると、UIがフリーズします。

理由
QElapsedTimerは時間の計測のみを行い、Qtのイベントループとは直接関係ありません。GUIアプリケーションでは、イベントループがユーザー入力や画面描画などのイベントを処理しています。長時間にわたるブロッキングループは、イベントループを停止させ、UIの応答性を失わせます。

解決策

  • より複雑な時間制限処理やバックグラウンド処理には、QThreadQt Concurrent、またはシグナル/スロットとQTimerを組み合わせた非同期処理を検討してください。QTimerは、指定された時間が経過した後にシグナルを発行するため、イベントループをブロックせずに時間イベントを処理するのに適しています。

  • 長時間かかる処理をQElapsedTimerで待機させる場合は、必ず定期的にQApplication::processEvents()を呼び出してイベントループを処理してください。

    QElapsedTimer timer;
    timer.start();
    qint64 timeoutMs = 5000; // 5秒
    
    while (!timer.hasExpired(timeoutMs)) {
        // 何らかの処理
        QApplication::processEvents(); // イベントを処理し、UIのフリーズを防ぐ
        // QThread::msleep(10); // 短時間スリープしてCPU負荷を軽減することも有効
    }
    

他のタイマーとの混同

問題
QElapsedTimerQTimerQTimeなどの他のQtのタイマークラスとの違いを理解せずに使用すると、期待と異なる結果になることがあります。

理由

  • QTime: 時刻(午前/午後、時間、分、秒)の取得や、日付に依存しない短期的な時間計測に使用。精度はQElapsedTimerほどではありません。
  • QTimer: 指定した時間間隔で繰り返し、または一度だけシグナル(timeout())を発行するために使用。イベントループと密接に連携し、GUIアプリケーションの応答性を保ちながら時間イベントを処理するのに適しています。
  • QElapsedTimer: 高精度な経過時間の計測に特化。イベントループとは独立して動作し、開始からの経過時間を計算します。一度開始すると、明示的にstart()restart()を呼び出さない限り、時間計測を継続します。

解決策
それぞれのタイマークラスの特性を理解し、目的の機能に合ったものを使用してください。



QElapsedTimer::hasExpired() は、ある操作が指定された時間内に完了したか、または特定の時間制限内でループを実行する必要がある場合に特に便利です。

例 1: シンプルなタイムアウト処理

これは、ある処理が指定された時間を超えて実行されるのを防ぐ最も基本的な例です。

#include <QCoreApplication>
#include <QElapsedTimer>
#include <QDebug>
#include <QThread> // QThread::msleep のために必要

// 時間のかかるダミー関数
void performSomeTask() {
    qDebug() << "  - タスクを実行中...";
    QThread::msleep(100); // 100ミリ秒間処理をブロック
}

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    QElapsedTimer timer;
    timer.start(); // タイマーを開始

    qint64 timeoutMs = 500; // 500ミリ秒 (0.5秒) のタイムアウト

    qDebug() << "タスク処理を開始します (タイムアウト: " << timeoutMs << "ミリ秒)";

    // タイムアウトするまでタスクを実行し続ける
    while (!timer.hasExpired(timeoutMs)) {
        performSomeTask();
    }

    qDebug() << "タイムアウトしました!処理を終了します。";
    qDebug() << "合計経過時間: " << timer.elapsed() << "ミリ秒";

    return 0;
}

説明

  1. QElapsedTimer timer; でタイマーオブジェクトを作成します。
  2. timer.start(); でタイマーをスタートさせ、時間の計測を開始します。
  3. qint64 timeoutMs = 500; で、500ミリ秒をタイムアウトとして設定します。
  4. while (!timer.hasExpired(timeoutMs)) ループでは、timerが開始されてからtimeoutMs(500ミリ秒)が経過していない間、performSomeTask()関数が繰り返し呼び出されます。
  5. 500ミリ秒が経過すると、hasExpired()trueを返し、ループが終了します。
  6. 最後に、timer.elapsed()で実際に経過した時間を表示します。この値は、timeoutMsとほぼ同じか、若干大きい値になるはずです(performSomeTaskの実行時間のため)。

例 2: GUIアプリケーションでの応答性を保つタイムアウト処理

GUIアプリケーションで、バックグラウンドでの時間のかかる処理中にUIがフリーズするのを防ぐためにQApplication::processEvents()と組み合わせる例です。

#include <QApplication>
#include <QPushButton>
#include <QLabel>
#include <QVBoxLayout>
#include <QElapsedTimer>
#include <QDebug>
#include <QThread> // ダミーの重い処理用

class MainWindow : public QWidget {
    Q_OBJECT
public:
    MainWindow(QWidget *parent = nullptr) : QWidget(parent) {
        setupUI();
    }

private slots:
    void onStartHeavyTask() {
        qDebug() << "重いタスクを開始します...";
        QLabel *statusLabel = findChild<QLabel*>("statusLabel");
        if (statusLabel) {
            statusLabel->setText("タスク実行中...");
        }

        QElapsedTimer timer;
        timer.start();
        qint64 timeoutMs = 3000; // 3秒のタイムアウト

        while (!timer.hasExpired(timeoutMs)) {
            // ダミーの重い処理
            // 実際には、ファイルの読み書き、複雑な計算など
            QThread::msleep(50); // 短時間スリープしてCPU負荷を軽減
            qDebug() << "  - 作業中... 経過時間: " << timer.elapsed() << "ms";

            // ★重要: イベントループを処理し、UIのフリーズを防ぐ
            QCoreApplication::processEvents();

            // 必要であれば、UIを更新
            if (statusLabel) {
                statusLabel->setText(QString("タスク実行中... (%1ms)").arg(timer.elapsed()));
            }
        }

        qDebug() << "重いタスクが終了しました (タイムアウトによる)。";
        if (statusLabel) {
            statusLabel->setText(QString("タスク完了!合計経過時間: %1ms").arg(timer.elapsed()));
        }
    }

private:
    void setupUI() {
        QVBoxLayout *layout = new QVBoxLayout(this);

        QLabel *titleLabel = new QLabel("QElapsedTimer hasExpired() GUI 例", this);
        layout->addWidget(titleLabel);

        QLabel *statusLabel = new QLabel("アイドル", this);
        statusLabel->setObjectName("statusLabel"); // findChildでアクセスできるようにオブジェクト名を設定
        layout->addWidget(statusLabel);

        QPushButton *startButton = new QPushButton("重いタスクを開始", this);
        connect(startButton, &QPushButton::clicked, this, &MainWindow::onStartHeavyTask);
        layout->addWidget(startButton);

        this->setWindowTitle("QElapsedTimer Demo");
        this->resize(400, 200);
    }
};

#include "main.moc" // mocファイルをインクルード

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);

    MainWindow w;
    w.show();

    return a.exec();
}

説明

  1. MainWindowクラスを作成し、ボタンとステータス表示用のラベルを配置します。
  2. onStartHeavyTask()スロット内で、QElapsedTimerを使って3秒のタイムアウトを設定します。
  3. while (!timer.hasExpired(timeoutMs)) ループ内で、ダミーの「重い処理」を実行します。
  4. 最も重要な点
    ループ内でQCoreApplication::processEvents()を定期的に呼び出しています。これにより、タイマーがタイムアウトするまでループが実行されている間も、Qtのイベントループが処理され、UIがフリーズせずに更新(ラベルのテキスト更新など)されるようになります。
  5. QThread::msleep(50); は、CPU使用率を下げつつ、処理が実際に「時間のかかる」ものであることをシミュレートするために使用しています。

例 3: ゲームループやアニメーションでのフレームレート制御

hasExpired()は、ゲームループなどでフレームレートを一定に保つための簡単な方法としても使用できます。

#include <QCoreApplication>
#include <QElapsedTimer>
#include <QDebug>
#include <QThread> // ダミーの描画処理用

const int TARGET_FPS = 60; // 目標フレームレート
const qint64 FRAME_MS = 1000 / TARGET_FPS; // 1フレームあたりの目標ミリ秒

// ダミーの描画処理
void renderFrame(int frameNumber) {
    qDebug() << "  - フレーム " << frameNumber << " を描画中...";
    // 実際にはここで描画API呼び出しやゲームロジック
    QThread::msleep(5); // 描画に5ミリ秒かかると仮定
}

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    QElapsedTimer frameTimer;
    int frameCount = 0;

    qDebug() << TARGET_FPS << " FPS を目指してゲームループを開始します...";

    // 継続的にフレームを生成する(実際にはイベントループで中断されるか、特定の条件で終了)
    while (frameCount < 300) { // 例として300フレームで終了
        frameTimer.restart(); // 各フレームの開始時にタイマーをリスタート

        // 描画処理
        renderFrame(frameCount);

        // フレームレートを調整するための待機
        // 目標フレーム時間 (FRAME_MS) に達するまで待機
        while (!frameTimer.hasExpired(FRAME_MS)) {
            // 何もしないか、他の軽い処理を行う
            // 無駄なCPU消費を避けるためにQThread::yieldCurrentThread()も考慮できるが、
            // 短時間の待機であればスピンループでも問題ない場合も。
            // 重い場合はQThread::msleep(1)などでCPU負荷を軽減
        }

        qDebug() << "  - フレーム " << frameCount << " 完了。経過時間: " << frameTimer.elapsed() << "ms";
        frameCount++;
    }

    qDebug() << "ゲームループ終了。";

    return 0;
}
  1. TARGET_FPSFRAME_MS を定義し、目標フレームレートと1フレームあたりの目標時間を設定します。
  2. frameTimer.restart(); を各フレームの開始時に呼び出し、そのフレームの計測を開始します。
  3. renderFrame() ダミー関数で描画処理をシミュレートします。
  4. while (!frameTimer.hasExpired(FRAME_MS)) ループを使用して、現在のフレームの処理が目標のFRAME_MSに達するまで待機します。これにより、フレームレートが目標値を超えて速くなりすぎるのを防ぎます。
  5. hasExpired() を使うことで、restart() からの経過時間がFRAME_MSに達したかどうかを簡単に判断できます。


QElapsedTimer::hasExpired() は主に「指定された時間以上が経過したかどうか」をポーリング(繰り返し確認)する際に使用されます。しかし、Qt には時間に関連するイベントを扱うための他の強力なメカニズムがあります。

QElapsedTimer::elapsed() と手動比較

hasExpired() の最も直接的な代替は、QElapsedTimer::elapsed() メソッドを呼び出し、その戻り値を自分でタイムアウト値と比較することです。

いつ使うか

  • hasExpired() と同じようなポーリングロジックを自分で明示的に書きたい場合。
  • hasExpired() が導入される前の古い Qt バージョンを使用している場合。


#include <QCoreApplication>
#include <QElapsedTimer>
#include <QDebug>
#include <QThread>

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    QElapsedTimer timer;
    timer.start();

    qint64 timeoutMs = 1000; // 1秒

    qDebug() << "タイマー開始。1秒経過するまで処理を続けます (手動比較)。";

    while (timer.elapsed() < timeoutMs) { // hasExpired() の代わりに elapsed() < timeoutMs
        qDebug() << "  - 処理中... 経過: " << timer.elapsed() << "ms";
        QThread::msleep(50);
    }

    qDebug() << "1秒が経過しました!処理を終了します。";
    qDebug() << "最終経過時間: " << timer.elapsed() << "ミリ秒";

    return 0;
}

hasExpired() との違い
機能的にはほぼ同じですが、hasExpired() はこの比較処理を内部でカプセル化したコンビニエンス関数です。

QTimer クラス(イベント駆動型タイムアウト)

GUIアプリケーションやイベントループ内で、指定された時間が経過した後に自動的に処理を実行したい場合に最適な方法です。QElapsedTimer::hasExpired() のようにポーリングループでUIをブロックするのを避けることができます。

いつ使うか

  • UIをフリーズさせずに、時間に関連するイベントを処理したい場合。
  • 指定された時間間隔で定期的に処理を実行したい場合(繰り返しタイマー)。
  • 指定された時間後に一度だけ処理を実行したい場合(ワンショットタイマー)。

例 (ワンショットタイマー)

#include <QCoreApplication>
#include <QTimer>
#include <QDebug>

class MyObject : public QObject {
    Q_OBJECT
public:
    MyObject(QObject *parent = nullptr) : QObject(parent) {
        qDebug() << "MyObject 作成";
    }

public slots:
    void startTimeout() {
        qDebug() << "ワンショットタイマーを開始します (3秒後)。";
        QTimer::singleShot(3000, this, &MyObject::onTimeout); // 3秒後にonTimeout()を呼び出す
    }

private slots:
    void onTimeout() {
        qDebug() << "★タイムアウトしました!処理を実行します。";
        QCoreApplication::quit(); // アプリケーションを終了
    }
};

#include "main.moc" // mocファイルをインクルード

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    MyObject obj;
    obj.startTimeout();

    // イベントループがQTimerのtimeout()シグナルを処理するまで待機
    return a.exec();
}

例 (繰り返しタイマー)

#include <QCoreApplication>
#include <QTimer>
#include <QDebug>

class PeriodicTask : public QObject {
    Q_OBJECT
public:
    PeriodicTask(QObject *parent = nullptr) : QObject(parent) {
        timer = new QTimer(this);
        connect(timer, &QTimer::timeout, this, &PeriodicTask::onPeriodicTimeout);
    }

    void start(int intervalMs) {
        qDebug() << "定期タスクを開始します (間隔: " << intervalMs << "ms)";
        timer->start(intervalMs); // 指定された間隔でtimeout()シグナルを発行
    }

private slots:
    void onPeriodicTimeout() {
        static int count = 0;
        qDebug() << "周期的なタイムアウトが発生しました!(" << ++count << "回目)";
        if (count >= 5) {
            timer->stop();
            qDebug() << "5回実行されたのでタイマーを停止します。";
            QCoreApplication::quit();
        }
    }

private:
    QTimer *timer;
};

#include "main.moc"

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    PeriodicTask task;
    task.start(1000); // 1秒ごとに実行

    return a.exec();
}

QElapsedTimer::hasExpired() との使い分け

  • QTimer
    非同期的な(ノンブロッキングな)イベント駆動型プログラミングで、「指定された時間後に何かをする」という場合に最適です。UIの応答性を保ちながら、時間に基づく処理を行うことができます。
  • QElapsedTimer::hasExpired()
    同期的な(ブロッキングの可能性がある)ループ内で「指定された時間以上が経過したか」をポーリングする際に適しています。システム負荷が高まる可能性があり、GUIアプリケーションではQApplication::processEvents()との併用が必須です。

QTime クラス(古い Qt バージョンでの代替)

QElapsedTimer は Qt 4.7 以降で導入されました。それ以前のバージョンでは、QTime が類似の機能を提供していました。ただし、QTime はシステムクロックに依存するため、QElapsedTimer のような高精度でモノトニックな時間計測はできません。

いつ使うか

  • 高精度が不要な、大まかな時間計測で十分な場合。
  • 非常に古い Qt バージョン(Qt 4.6以前など)で作業する必要がある場合。


#include <QCoreApplication>
#include <QTime>
#include <QDebug>
#include <QThread>

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    QTime time;
    time.start(); // タイマーを開始

    qint64 timeoutMs = 1000; // 1秒

    qDebug() << "タイマー開始。1秒経過するまで処理を続けます (QTimeを使用)。";

    while (time.elapsed() < timeoutMs) {
        qDebug() << "  - 処理中... 経過: " << time.elapsed() << "ms";
        QThread::msleep(50);
    }

    qDebug() << "1秒が経過しました!処理を終了します。";
    qDebug() << "最終経過時間: " << time.elapsed() << "ミリ秒";

    return 0;
}

QElapsedTimer との違い

  • 推奨
    新しいコードでは、特殊な理由がない限りQElapsedTimerの使用が強く推奨されます。
  • 精度と安定性
    QElapsedTimer はモノトニッククロック(時間的に常に前進し、システム時刻の調整に影響されない)を使用するため、QTime よりも正確で安定した経過時間を提供します。QTime は壁時計時間(wall-clock time)に基づいているため、システム時刻が変更されると計測結果が狂う可能性があります。

スレッド(QThread)と待機(QThread::sleep/msleep/usleep)

時間のかかる処理をメインスレッド(UIスレッド)から分離し、別のスレッドで実行することで、UIの応答性を保つことができます。スレッド内でQThread::msleep()などを使って意図的に待機させることもできます。

いつ使うか

  • 決まった時間だけ処理を停止させたい場合(QElapsedTimerQTimerとは目的が異なる)。
  • 時間のかかる(CPU集中型またはI/O集中型)処理があり、その処理中にUIをフリーズさせたくない場合。

例 (スレッド内の処理)

#include <QCoreApplication>
#include <QThread>
#include <QDebug>
#include <QElapsedTimer> // スレッド内でhasExpired()も利用可能

class WorkerThread : public QThread {
    Q_OBJECT
public:
    WorkerThread(QObject *parent = nullptr) : QThread(parent) {}

protected:
    void run() override {
        qDebug() << "ワーカーSスレッド: 開始";
        QElapsedTimer timer;
        timer.start();
        qint64 timeoutMs = 5000; // 5秒間処理を実行

        while (!timer.hasExpired(timeoutMs)) {
            qDebug() << "ワーカーSスレッド: 作業中... 経過: " << timer.elapsed() << "ms";
            QThread::msleep(100); // 短時間スリープ
        }
        qDebug() << "ワーカーSスレッド: タイムアウト!処理を終了します。";
    }
};

#include "main.moc"

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    WorkerThread worker;
    worker.start(); // スレッドを開始

    qDebug() << "メインスレッド: ワーカーの完了を待っています...";
    // ここでメインスレッドはUIイベントなどを処理し続ける

    // worker.wait(); // 必要であれば、メインスレッドがワーカーの終了を待つ
    // ただし、GUIアプリではwait()はUIをブロックするので避けるべき

    QTimer::singleShot(6000, &a, &QCoreApplication::quit); // 6秒後にアプリを終了

    return a.exec();
}
  • スレッドは、時間のかかるタスクをバックグラウンドで実行し、UIの応答性を維持するためのQtの主要なメカニズムです。hasExpired() はスレッド内で使用することもできますが、スレッドの主な目的は時間計測ではなく、並行処理です。
  • QElapsedTimer::hasExpired() は、主に単一スレッド内での時間計測とフロー制御に使用されます。
  • QThread
    時間のかかる処理をUIスレッドから分離し、アプリケーションの応答性を維持する場合に最適です。時間計測そのものよりも、並行処理と応答性維持が目的です。
  • QTime
    QElapsedTimerが利用できない古いQtバージョンや、壁時計時間に基づく大まかな時間計測で十分な場合に限定して使用します。
  • QTimer
    非同期的なイベント駆動型のタイムアウト処理に最適です。GUIアプリケーションの応答性を維持しながら、指定時間後に一度だけ、または定期的に処理を実行したい場合にこれを使用します。ほとんどのUI関連のタイマー処理はQTimerで行うべきです。
  • QElapsedTimer::hasExpired() (または elapsed() と手動比較)
    主に同期的な(ブロッキング)ループ内で、高精度な経過時間をチェックし、特定の時間制限内での処理を行う場合に適しています。GUIアプリケーションではQApplication::processEvents()との併用が推奨されます。