タイマーを使ってQt Widgetsでサブウィンドウを動かす:QMdiSubWindow::timerEvent()の応用例
例:ウィジェットの揺れアニメーション
以下は、QMdiSubWindow を左右に揺らすアニメーションを作成する例です。
class WigglyWindow : public QMDISubWindow {
public:
WigglyWindow(QWidget *parent = nullptr);
protected:
void timerEvent(QTimerEvent *event) override;
private:
int m_angle; // 現在の角度
};
WigglyWindow::WigglyWindow(QWidget *parent) : QMDISubWindow(parent) {
m_angle = 0;
// タイマーを作成し、10ミリ秒ごとに期限切れになるように設定
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &WigglyWindow::timerEvent);
timer->start(10);
}
void WigglyWindow::timerEvent(QTimerEvent *event) {
// 角度を更新
m_angle = (m_angle + 5) % 360;
// ウィジェットを回転
setContentsMargins(m_angle, 0, 0, 0);
}
この例では、timerEvent()
メソッド内で m_angle
変数を5度ずつ更新しています。その後、setContentsMargins()
メソッドを使用して、ウィジェットを m_angle
度回転させています。これにより、ウィジェットが左右に揺れるアニメーションが作成されます。
QMdiSubWindow::timerEvent() メソッドは、さまざまなアニメーションや時間依存タスクに使用できます。以下は、いくつかの例です。
- カスタムグラフィックエフェクトの適用
- ウィジェットの位置変更
- ウィジェットのサイズ変更
- ウィジェットのフェードイン/フェードアウト
ウィジェットのフェードイン/フェードアウト
class FadeWindow : public QMDISubWindow {
public:
FadeWindow(QWidget *parent = nullptr);
protected:
void timerEvent(QTimerEvent *event) override;
private:
int m_opacity; // 現在の不透明度
};
FadeWindow::FadeWindow(QWidget *parent) : QMDISubWindow(parent) {
m_opacity = 0;
// タイマーを作成し、25ミリ秒ごとに期限切れになるように設定
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &FadeWindow::timerEvent);
timer->start(25);
}
void FadeWindow::timerEvent(QTimerEvent *event) {
// 不透明度を更新
if (m_opacity < 255) {
m_opacity += 5;
} else {
m_opacity = 0;
}
// ウィジェットの不透明度を設定
setWindowOpacity(m_opacity / 255.0);
}
ウィジェットのサイズ変更
class ResizeWindow : public QMDISubWindow {
public:
ResizeWindow(QWidget *parent = nullptr);
protected:
void timerEvent(QTimerEvent *event) override;
private:
int m_width; // 現在の幅
int m_height; // 現在の高さ
};
ResizeWindow::ResizeWindow(QWidget *parent) : QMDISubWindow(parent) {
m_width = 100;
m_height = 100;
// タイマーを作成し、50ミリ秒ごとに期限切れになるように設定
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &ResizeWindow::timerEvent);
timer->start(50);
}
void ResizeWindow::timerEvent(QTimerEvent *event) {
// サイズを更新
if (m_width < 400 && m_height < 400) {
m_width += 10;
m_height += 10;
} else {
m_width = 100;
m_height = 100;
}
// ウィジェットのサイズを設定
resize(m_width, m_height);
}
この例では、timerEvent()
メソッド内で m_width
と m_height
変数を10ずつ増減しています。その後、resize()
メソッドを使用して、ウィジェットのサイズを設定しています。これにより、ウィジェットが徐々に拡大縮小するアニメーションが作成されます。
class MoveWindow : public QMDISubWindow {
public:
MoveWindow(QWidget *parent = nullptr);
protected:
void timerEvent(QTimerEvent *event) override;
private:
int m_x; // 現在の X 座標
int m_y; // 現在の Y 座標
};
MoveWindow::MoveWindow(QWidget *parent) : QMDISubWindow(parent) {
m_x = 0;
m_y = 0;
// タイマーを作成し、30ミリ秒ごとに期限切れになるように設定
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &MoveWindow::timerEvent);
timer->start(30);
}
void MoveWindow::timerEvent(QTimerEvent *event) {
// 位置を更新
if (m_x < 200 && m_y < 200) {
m_x += 5;
m_y += 5;
} else {
m_x = 0;
m_y = 0;
}
// ウィジェットの位置を設定
move(m_x, m_y);
}
QPropertyAnimation を使用する
QPropertyAnimation は、Qt アニメーションフレームワークの一部であり、ウィジェットのプロパティをアニメーション化するための使いやすい方法を提供します。QMdiSubWindow の位置、サイズ、不透明度などのプロパティをアニメーション化するために使用できます。
QPropertyAnimation *animation = new QPropertyAnimation(window, "geometry");
animation->setDuration(1000); // アニメーションの長さ (ミリ秒)
animation->setStartValue(window->geometry()); // 開始値
animation->setEndValue(QRect(200, 100, 300, 200)); // 終了値
animation->start();
この例では、window
ウィジェットの位置を (200, 100) から (300, 200) に 1 秒間かけてアニメーション化しています。
QStateMachine を使用する
QStateMachine は、複雑なアニメーションやステートマシンベースのロジックをモデル化するためのフレームワークです。複数のアニメーションを組み合わせたり、条件分岐などのロジックを組み込んだりすることができます。
QStateMachine *machine = new QStateMachine(window);
QState *initialState = new QState(machine);
QState *finalState = new QState(machine);
initialState->addTransition(QEvent::TimerEvent, finalState, 1000); // 1 秒後に finalState に遷移
finalState->addTransition(QEvent::TimerEvent, initialState, 1000); // 1 秒後に initialState に遷移
machine->addState(initialState);
machine->addState(finalState);
machine->setInitialState(initialState);
machine->start();
この例では、window
ウィジェットの位置を 1 秒間隔で (200, 100) と (300, 200) の間で切り替えます。
カスタムタイマーを実装する
QTimerEvent を使用せずに、独自のタイマーイベントを処理することもできます。これにより、よりきめ細かな制御が可能になりますが、コードが複雑になる可能性があります。
class MyWindow : public QMDISubWindow {
public:
MyWindow(QWidget *parent = nullptr);
protected:
void paintEvent(QPaintEvent *event) override;
void timer() override;
private:
int m_angle; // 現在の角度
};
MyWindow::MyWindow(QWidget *parent) : QMDISubWindow(parent) {
m_angle = 0;
// タイマーを開始
startTimer(10); // 10ミリ秒ごとに timer() メソッドを呼び出す
}
void MyWindow::paintEvent(QPaintEvent *event) {
QPainter painter(this);
// ウィジェットを回転
painter.translate(width() / 2, height() / 2);
painter.rotate(m_angle);
// ウィジェットの内容を描画
// ...
}
void MyWindow::timer() {
// 角度を更新
m_angle = (m_angle + 5) % 360;
// ウィジェットを再描画
update();
}