📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)

 
(同じ利用者による、間の6版が非表示)
1行目: 1行目:
== 概要 ==
== 概要 ==
Qtにおいて、<code>QTimer</code>クラスを使用して、様々な処理を実行する手順を記載する。<br>
<code>QTimer</code>クラスは、時間ベースのイベントを処理するためのクラスである。<br>
主に、一定の間隔で特定の処理を実行する場合に使用する。<br>
<br>
<code>QTimer</code>クラスは、まず、<code>QTimer</code>オブジェクトを作成して、<code>start</code>メソッドを呼び出して起動する。<br>
タイマ時間が過ぎると、<code>timeout</code>シグナルが発行される。<br>
このシグナルを任意のスロットに接続することにより、定期的に処理を実行することができる。<br>
<br>
タイマの精度は、OSやハードウェアに依存する。<br>
ミリ秒単位での制御が可能であるが、極端に短い間隔を設定する場合、システムの負荷が高くなる可能性があるため注意が必要である。<br>
<br>
<code>QTimer</code>クラスには、単発のタイマと繰り返しのタイマが存在する。<br>
単発のタイマは<code>singleShot</code>メソッド (staticメソッド) を使用してに設定することができる。<br>
一方、繰り返しのタイマは、QTimerオブジェクトを使用して実装する。<br>
<br>
<code>QTimer</code>クラスのメリットとして、Qtのイベントループと統合されているため、他のQtのコンポーネントとシームレスに連携できることが挙げられる。<br>
また、マルチスレッド環境でも安全に使用できるよう設計されている。<br>
<br>
タイマの制御には、<code>start</code>メソッドの他に<code>stop</code>メソッドがあり、これを使用してタイマを一時停止することができる。<br>
また、<code>isActive</code>メソッドを使用して、タイマが現在アクティブかどうかを確認することもできる。<br>
<br>
<code>QTimer</code>クラスは、UIの更新、ネットワーク操作のタイムアウト、アニメーションの制御等、様々な用途に活用できる便利なクラスである。<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>
==== QWidgetアプリケーション ====
以下の例では、QTimerクラスの単発タイマ機能を使用して、UIを定期的に更新している。<br>
<br>
具体的なタイマの動作を以下に示す。<br>
* startCountdownスロットにて、10秒のカウントダウンを開始する。
* updateTimerスロットにて、1秒ごとにカウントダウンを更新して、UIを更新する。
* QTimer::singleShotメソッドを再帰的に使用して、1秒ごとの更新を実現する。
<br>
<syntaxhighlight lang="c++">
// CountdownWindow.hファイル
#include <QApplication>
#include <QMainWindow>
#include <QVBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QTimer>
class CountdownWindow : public QMainWindow
{
    Q_OBJECT
private:
    int m_secondsLeft;
    QLabel *m_timeLabel;
    QPushButton *m_startButton;
public:
    CountdownWindow(QWidget *parent = nullptr) : QMainWindow(parent), m_secondsLeft(10)
    {
      setWindowTitle("Countdown Timer");
      QWidget *centralWidget = new QWidget(this);
      setCentralWidget(centralWidget);
      QVBoxLayout *layout = new QVBoxLayout(centralWidget);
      m_timeLabel = new QLabel("Time left: 10 seconds", this);
      layout->addWidget(m_timeLabel);
      m_startButton = new QPushButton("Start Countdown", this);
      layout->addWidget(m_startButton);
      connect(m_startButton, &QPushButton::clicked, this, &CountdownWindow::startCountdown);
    }
private slots:
    void startCountdown()
    {
      m_secondsLeft = 10;
      updateDisplay();
      m_startButton->setEnabled(false);
      // 1秒ごとにupdateTimerを呼び出す
      QTimer::singleShot(1000, this, &CountdownWindow::updateTimer);
    }
    void updateTimer()
    {
      m_secondsLeft--;
      updateDisplay();
      if (m_secondsLeft > 0) {
          // カウントダウンが終わっていない場合、再度タイマをセット
          QTimer::singleShot(1000, this, &CountdownWindow::updateTimer);
      }
      else {
          m_startButton->setEnabled(true);
      }
    }
    void updateDisplay()
    {
      m_timeLabel->setText(QString("Time left: %1 seconds").arg(m_secondsLeft));
    }
};
</syntaxhighlight>
<br>
<syntaxhighlight lang="c++">
// main.cppファイル
#include "CountdownWindow.h"
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    CountdownWindow window;
    window.resize(300, 150);
    window.show();
    return app.exec();
}
</syntaxhighlight>
<br><br>
<br><br>


== タイマイベントの使用例 ==
== 繰り返しタイマ ==
以下の例では、ダイアログを開いて画像を表示している。<br>
以下の例では、ダイアログを開いて画像を表示している。<br>
1秒ごとに画像の大きさを変化させる。<br>
1秒ごとに画像の大きさを変化させる。<br>
108行目: 289行目:
<br><br>
<br><br>


== QTimerを即タイムアウトする ==
== タイマの即時タイムアウト ==
<code>QTimer</code>クラスの<code>timeout</code>メソッドに、<code>{}</code>を渡す。<br>
<code>QTimer</code>クラスの<code>timeout</code>メソッドに、<code>{}</code>を渡す。<br>
  <syntaxhighlight lang="c++">
  <syntaxhighlight lang="c++">
121行目: 302行目:
そして、プッシュボタンを押下し続けている間、1秒毎に1増加している。<br>
そして、プッシュボタンを押下し続けている間、1秒毎に1増加している。<br>
  <syntaxhighlight lang="c++">
  <syntaxhighlight lang="c++">
  // MainWindow.h
  // MainWindow.hファイル
#pragma once
   
   
  #include <QMainWindow>
  #include <QMainWindow>
131行目: 310行目:
  {
  {
     Q_OBJECT
     Q_OBJECT
private:
    Ui::MainWindow          *ui;
    std::unique_ptr<QTimer> m_Timer;
    int                    m_Val;
private:
    void timerFunc()
    {
      m_Val++;
      ui->label->setText(QString::number(m_Val));
    }
   
   
  public:
  public:
     explicit MainWindow(QWidget *parent = nullptr);
     explicit MainWindow(QWidget *parent = nullptr) : QMainWindow(parent), ui(new Ui::MainWindow), m_Timer(nullptr), m_Val(0)
     ~MainWindow();
    {
      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()
    {
      delete ui;
    }
   
   
  private slots:
  private slots:
     void on_pushButton_pressed();
     void on_pushButton_pressed()
    void on_pushButton_released();
    {
      m_Timer->timeout({});
      m_Timer->start(1000);
    }
   
   
private:
    void on_pushButton_released()
     Ui::MainWindow *ui;
     {
    std::unique_ptr<QTimer> m_Timer;
      m_Timer->stop();
    int m_Val;
     }
     void timerFunc();
  };
  };
  </syntaxhighlight>
  </syntaxhighlight>
<br>
<br>
  <syntaxhighlight lang="c++">
  <syntaxhighlight lang="c++">
  // MainWindow.cpp
  // main.cppファイル
   
   
  #include <MainWindow.h>
  #include "MainWindow.h"
   
   
  MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), m_Timer(nullptr), m_Val(0)
  int main(int argc, char *argv[])
  {
  {
     ui->setupUi(this);
     QApplication app(argc, argv);
   
   
     ui->label->setText(QString::number(val));
     MainWindow window;
    window.show();
   
   
     m_Timer = std::make_unique<QTimer>(this);
     return app.exec();
}
</syntaxhighlight>
<br><br>
 
== タイマを使用したスリープ ==
以下の例では、<code>QEventLoop</code>クラスを使用したスリープ処理である。<br>
これにより、CPUに負荷を掛けずにイベントシステムを使用してタイマを終了することができる。<br>
<br>
ボタン押下時にDelay関数を実行して、3秒間の待機を実演している。<br>
待機中もUIは応答可能であり、他のイベントを処理することができる。<br>
<br>
具体的な動作を以下に示す。<br>
* EventLoopクラスの使用
*: <code>QEventLoop</code>クラスは、イベントの処理を一時的に独立したループで行うことを可能にする。
*: これにより、アプリケーションのメインイベントループをブロックせずに待機することができる。
* QTimerクラスとの組み合わせ
*: <code>QTimer</code>クラスは、指定された時間後に<code>timeout</code>シグナルを発行する。
*: このシグナルを<code>QEventLoop::quit</code>スロットに接続することにより、タイマが満了した時にループを終了する。
* 効率的な待機
*: この方法では、ビジーウェイトを使用せずに待機するため、CPUリソースを節約できる。
*: アプリケーションは他のイベントに応答可能な状態を維持する。
* 非同期処理
*: onDelayButtonClickedスロットでは、<code>QTimer::singleShot</code>メソッドを使用して、performDelayを非同期で呼び出している。
*: これにより、UIのフリーズを防いで、ユーザエクスペリエンスを向上させている。
* 状態表示
*: QLabelを使用して、遅延の開始と終了を表示している。
*: これにより、ユーザに処理の進行状況を視覚的に伝えることができる。
<br>
<syntaxhighlight lang="c++">
// MainWindow.hファイル
   
   
    connect(m_Timer, &QTimer::timeout, this, &MainWindow::timerFunc);
#include <QMainWindow>
  }
#include <QEventLoop>
#include <QPushButton>
#include <QVBoxLayout>
#include <QLabel>
  #include <QTimer>
   
   
  MainWindow::~MainWindow()
  class MainWindow : public QMainWindow
  {
  {
     delete ui;
     Q_OBJECT
  }
private:
    QLabel *m_statusLabel;
public:
    MainWindow(QWidget *parent = nullptr) : QMainWindow(parent)
    {
      QWidget *centralWidget = new QWidget(this);
      setCentralWidget(centralWidget);
      QVBoxLayout *layout = new QVBoxLayout(centralWidget);
      QPushButton *delayButton = new QPushButton("Start 3 Second Delay", this);
      layout->addWidget(delayButton);
   
      m_statusLabel = new QLabel("Ready", this);
      layout->addWidget(m_statusLabel);
      connect(delayButton, &QPushButton::clicked, this, &MainWindow::onDelayButtonClicked);
    }
    void Delay(int ms)
    {
      QEventLoop loop;
      QTimer    timer;
      timer.setSingleShot(true);
      connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
      timer.start(ms);
   
   
void MainWindow::on_pushButton_pressed()
      loop.exec();
{
     }
    m_Timer->timeout({});
     m_Timer->start(1000);
}
   
   
  void MainWindow::on_pushButton_released()
  private slots:
{
    void onDelayButtonClicked()
    m_Timer->stop();
    {
}
      m_statusLabel->setText("Starting delay...");
      QTimer::singleShot(0, this, &MainWindow::performDelay);
    }
   
   
void MainWindow::timerFunc()
    void performDelay()
{
    {
    m_Val++;
      Delay(3000); // 3秒の遅延
    ui->label->setText(QString::number(m_Val));
      m_statusLabel->setText("Delay finished!");
  }
    }
  };
  </syntaxhighlight>
  </syntaxhighlight>
<br><br>
<br>
 
== タイマを使用したスリープ ==
以下の例では、<code>QEventLoop</code>クラスを使用したスリープ処理である。<br>
これは、CPUに負荷を掛けずにイベントシステムを使用してタイマを終了することができる。<br>
  <syntaxhighlight lang="c++">
  <syntaxhighlight lang="c++">
  #include <QTimer>
// main.cppファイル
  #include "MainWindow.h"
   
   
  void MainWindow::Delay(int ms)
  int main(int argc, char *argv[])
  {
  {
     QEventLoop loop;
     QApplication app(argc, argv);
    QTimer Timer(this);
   
   
     connect(&Timer, &QTimer::timeout, &loop, &QEventLoop::quit);
     MainWindow window;
     Timer.start(ms);
     window.show();
   
   
     loop.exec();
     return app.exec();
}
 }
  </syntaxhighlight>
  </syntaxhighlight>
<br><br>
<br><br>