スレッドとUIコンポーネントの安全な状態更新
メインスレッド以外のスレッドがUI要素を直接操作すると不整合が発生するため、Qtフレームワークでは非同期通信メカニズムを提供しています。本手法の核心は、ワーカースレッドがUI更新要求をメインスレッドに伝達するためのイベント駆動モデルにあります。
カスタムイベントによる状態通知の実装
シグナル/スロット以外に、QEventを継承したカスタムイベントを使用する方法があります。この手法では、ワーカースレッドがイベントキューに更新要求を非同期投入し、メインスレッドがイベントループで処理します。
イベント定義の実装例
#ifndef UI_UPDATE_EVENT_H
#define UI_UPDATE_EVENT_H
#include <QEvent>
#include <QString>
class UiUpdateEvent : public QEvent {
QString m_content;
public:
static const QEvent::Type UPDATE_TYPE =
static_cast<QEvent::Type>(QEvent::User + 100);
explicit UiUpdateEvent(const QString& text)
: QEvent(UPDATE_TYPE), m_content(text) {}
QString content() const { return m_content; }
};
#endif // UI_UPDATE_EVENT_H
ワーカースレッドの実装
#include "UiUpdateEvent.h"
#include <QThread>
class StatusMonitorThread : public QThread {
Q_OBJECT
public:
explicit StatusMonitorThread(QObject* target)
: QThread(target) {}
protected:
void run() override {
QCoreApplication::postEvent(
parent(),
new UiUpdateEvent("初期化中")
);
for (int step = 0; step < 15; ++step) {
QCoreApplication::postEvent(
parent(),
new UiUpdateEvent(QString("処理: %1%").arg(step * 7))
);
QThread::msleep(500);
}
QCoreApplication::postEvent(
parent(),
new UiUpdateEvent("完了")
);
}
};
メインウィンドウのイベントハンドリング
#include "UiUpdateEvent.h"
#include <QTextEdit>
class MainWindow : public QWidget {
Q_OBJECT
StatusMonitorThread m_worker;
QTextEdit m_logArea;
public:
MainWindow(QWidget* parent = nullptr) : QWidget(parent) {
m_logArea.setGeometry(20, 20, 300, 200);
m_worker.start();
}
protected:
bool event(QEvent* e) override {
if (e->type() == UiUpdateEvent::UPDATE_TYPE) {
auto* update = static_cast<UiUpdateEvent*>(e);
m_logArea.append(update->content());
return true;
}
return QWidget::event(e);
}
};
実装の重要なポイント
- カスタムイベントはヒープ領域で動的生成必須(
new使用) postEvent()による非同期投入でイベントループが安全に処理- イベントタイプは
QEvent::User以上の値で固有性を確保 - 親オブジェクト経由でイベント送信先を指定する設計パターン
ワーカースレッドのライフサイクル管理では、イベント投入時に親オブジェクトの有効性を確認する必要があります。イベント処理はメインスレッドのイベントループによって自動的に削除されるため、メモリリークのリスクを回避できます。