「Qtの基礎 - タイマ」の版間の差分
(→概要) |
|||
24行目: | 24行目: | ||
<br><br> | <br><br> | ||
== | == 単発のタイマ == | ||
以下の例では、単発タイマを使用して、指定時間後に1度だけメッセージを表示している。<br> | |||
<syntaxhighlight lang="c++"> | |||
// TimerExample.hファイル | |||
#include <QCoreApplication> | |||
#include <QTimer> | |||
#include <stdexcept> | |||
#include <QDebug> | |||
class TimerExample : public QObject | |||
{ | |||
Q_OBJECT | |||
public: | |||
TimerExample(QObject *parent = nullptr) : QObject(parent) {} | |||
void startTimer(int milliseconds) | |||
{ | |||
// startTimer(0)のように呼び出す場合は例外エラーとする | |||
try { | |||
if (milliseconds <= 0) { | |||
throw std::invalid_argument("Timer duration must be positive"); | |||
} | |||
QTimer::singleShot(milliseconds, this, &TimerExample::onTimeout); | |||
qDebug() << "Timer started for" << milliseconds << "milliseconds"; | |||
} | |||
catch (const std::exception& e) { | |||
qCritical() << "エラー: " << e.what(); | |||
} | |||
} | |||
private slots: | |||
void onTimeout() | |||
{ | |||
qDebug() << "Timer expired!"; | |||
emit finished(); | |||
} | |||
signals: | |||
void finished(); | |||
}; | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// main.cppファイル | |||
#include "TimerExample.h" | |||
int main(int argc, char *argv[]) | |||
{ | |||
QCoreApplication a(argc, argv); | |||
TimerExample example; | |||
QObject::connect(&example, &TimerExample::finished, &a, &QCoreApplication::quit); | |||
example.startTimer(5000); // 5秒後にタイマイベント開始 | |||
return a.exec(); | |||
} | |||
</syntaxhighlight> | |||
<br><br> | |||
== 繰り返しタイマ == | |||
以下の例では、ダイアログを開いて画像を表示している。<br> | 以下の例では、ダイアログを開いて画像を表示している。<br> | ||
1秒ごとに画像の大きさを変化させる。<br> | 1秒ごとに画像の大きさを変化させる。<br> |
2024年9月5日 (木) 00:28時点における版
概要
QTimer
クラスは、時間ベースのイベントを処理するためのクラスである。
主に、一定の間隔で特定の処理を実行する場合に使用する。
QTimer
クラスは、まず、QTimer
オブジェクトを作成して、start
メソッドを呼び出して起動する。
タイマ時間が過ぎると、timeout
シグナルが発行される。
このシグナルを任意のスロットに接続することにより、定期的に処理を実行することができる。
タイマの精度は、OSやハードウェアに依存する。
ミリ秒単位での制御が可能であるが、極端に短い間隔を設定する場合、システムの負荷が高くなる可能性があるため注意が必要である。
QTimer
クラスには、単発のタイマと繰り返しのタイマが存在する。
単発のタイマはsingleShot
メソッド (staticメソッド) を使用してに設定することができる。
一方、繰り返しのタイマは、QTimerオブジェクトを使用して実装する。
QTimer
クラスのメリットとして、Qtのイベントループと統合されているため、他のQtのコンポーネントとシームレスに連携できることが挙げられる。
また、マルチスレッド環境でも安全に使用できるよう設計されている。
タイマの制御には、start
メソッドの他にstop
メソッドがあり、これを使用してタイマを一時停止することができる。
また、isActive
メソッドを使用して、タイマが現在アクティブかどうかを確認することもできる。
QTimer
クラスは、UIの更新、ネットワーク操作のタイムアウト、アニメーションの制御等、様々な用途に活用できる便利なクラスである。
ただし、過度に多くのタイマを同時に使用する場合は、アプリケーションのパフォーマンスに影響を与える可能性があるため、適切な設計と使用が求められる。
単発のタイマ
以下の例では、単発タイマを使用して、指定時間後に1度だけメッセージを表示している。
// TimerExample.hファイル
#include <QCoreApplication>
#include <QTimer>
#include <stdexcept>
#include <QDebug>
class TimerExample : public QObject
{
Q_OBJECT
public:
TimerExample(QObject *parent = nullptr) : QObject(parent) {}
void startTimer(int milliseconds)
{
// startTimer(0)のように呼び出す場合は例外エラーとする
try {
if (milliseconds <= 0) {
throw std::invalid_argument("Timer duration must be positive");
}
QTimer::singleShot(milliseconds, this, &TimerExample::onTimeout);
qDebug() << "Timer started for" << milliseconds << "milliseconds";
}
catch (const std::exception& e) {
qCritical() << "エラー: " << e.what();
}
}
private slots:
void onTimeout()
{
qDebug() << "Timer expired!";
emit finished();
}
signals:
void finished();
};
// main.cppファイル
#include "TimerExample.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
TimerExample example;
QObject::connect(&example, &TimerExample::finished, &a, &QCoreApplication::quit);
example.startTimer(5000); // 5秒後にタイマイベント開始
return a.exec();
}
繰り返しタイマ
以下の例では、ダイアログを開いて画像を表示している。
1秒ごとに画像の大きさを変化させる。
ダイアログを閉じる時、タイマを解除する。
// MainWindow.h
private:
int m_TimerID;
int m_AdjustGraphicSize;
std::unique_ptr<QLabel> m_pLabel;
private:
void GraphicTimer();
protected:
void timerEvent(QTimerEvent *pEvent);
private slots:
void CloseDialog();
// MainWindow.cpp
// モーダルダイアログに画像を貼り付けて、1秒のタイマを設定して表示する
void MainWindow::GraphicTimer()
{
m_AdjustGraphicSize = 1;
m_pLabel = std:make_unique<QLabel>;
m_pLabel->setFixedSize(32, 32);
m_pLabel->setScaledContents(true);
QPixmap pixmap = QApplication::style()->standardPixmap(QStyle::SP_FileDialogContentsView);
m_pLabel->setPixmap(pixmap);
std::unique_ptr<QHBoxLayout> pHbox1 = std::make_unique<QHBoxLayout>;
pHbox1->addWidget(m_pLabel);
pHbox1->addStretch();
std::unique_ptr<QPushButton> pBtn = std::make_unique<QPushButton>(tr("閉じる"));
pBtn->setFixedSize(80, 28);
// プッシュボタンのシグナルとCloseDialogスロットを接続する
connect(pBtn, SIGNAL(clicked()), this, SLOT(CloseDialog()));
std::unique_ptr<QHBoxLayout> pHbox2 = std::make_unique<QHBoxLayout>;
pHbox2->addStretch();
pHbox2->addWidget(pBtn);
pHbox2->addStretch();
std::unique_ptr<QVBoxLayout> pVbox = std::make_unique<QVBoxLayout>;
pVbox->addLayout(pHbox1);
pVbox->addStretch();
pVbox->addLayout(pHbox2);
std::unique_ptr<QDialog> Dlg = std::make_unique<QDialog>(this, 0);
Dlg->setModal(true);
Dlg->setSizeGripEnabled(false);
Dlg->setWindowTitle(tr("タイマテスト"));
Dlg->setMinimumSize(240, 280);
Dlg->setMaximumSize(240, 280);
Dlg->setLayout(pVbox);
m_TimerID = startTimer(1000);
Dlg->exec();
killTimer(m_TimerID);
}
// イベント処理
// ラベルサイズを32[px]〜200[px]の範囲で16[px]ずつ増減する
// m_AdjustGraphicSizeの値により大小を決める
// 全てのタイマイベントは当メソッドに来るため、タイマIDで処理を振り分ける
// 変数m_AdjustGraphicSizeには、1または-1が代入される
void MainWindow::timerEvent(QTimerEvent *pEvent)
{
if(pEvent->timerId() == m_TimerID)
{
int sz = m_pLabel->width() + m_AdjustGraphicSize * 16;
m_pLabel->setFixedSize(sz, sz);
if(sz > 200 || sz <= 32)
{
m_AdjustGraphicSize *= -1;
}
}
}
// ダイアログの終了処理
// 送信元のウインドウがダイアログの場合、doneで終了する(doneの引数は、execの戻り値である)
void MainWindow::CloseDialog()
{
QWidget *pWindow = static_cast<QWidget *>(sender())->window();
if(pWindow->inherits("QDialog"))
{
QDialog *Dlg = static_cast<QDialog *>(pWindow);
Dlg->done(0);
}
}
QTimerを即タイムアウトする
QTimer
クラスのtimeout
メソッドに、{}
を渡す。
timer->timeout({});
一般的に、timeout
シグナルを接続したスロット関数では、以降変更しない場合、
QTimer
クラスのstart
メソッドを実行する前に、直接スロット関数を1度呼ぶ。
しかし、接続するスロット関数を動的に変更する場合、timeout
メソッドを呼ぶだけの方が便利である。
以下の例では、プッシュボタンとラベルを配置して、プッシュボタンを押下した直後にタイマを開始している。
そして、プッシュボタンを押下し続けている間、1秒毎に1増加している。
// MainWindow.h
#pragma once
#include <QMainWindow>
#include <memory>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButton_pressed();
void on_pushButton_released();
private:
Ui::MainWindow *ui;
std::unique_ptr<QTimer> m_Timer;
int m_Val;
void timerFunc();
};
// MainWindow.cpp
#include <MainWindow.h>
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), m_Timer(nullptr), m_Val(0)
{
ui->setupUi(this);
ui->label->setText(QString::number(val));
m_Timer = std::make_unique<QTimer>(this);
connect(m_Timer, &QTimer::timeout, this, &MainWindow::timerFunc);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_pressed()
{
m_Timer->timeout({});
m_Timer->start(1000);
}
void MainWindow::on_pushButton_released()
{
m_Timer->stop();
}
void MainWindow::timerFunc()
{
m_Val++;
ui->label->setText(QString::number(m_Val));
}
タイマを使用したスリープ
以下の例では、QEventLoop
クラスを使用したスリープ処理である。
これは、CPUに負荷を掛けずにイベントシステムを使用してタイマを終了することができる。
#include <QTimer>
void MainWindow::Delay(int ms)
{
QEventLoop loop;
QTimer Timer(this);
connect(&Timer, &QTimer::timeout, &loop, &QEventLoop::quit);
Timer.start(ms);
loop.exec();
}