Qtの基礎 - タイマ

提供:MochiuWiki : SUSE, EC, PCB
2022年1月15日 (土) 18:46時点におけるWiki (トーク | 投稿記録)による版 (→‎QTimerを即タイムアウトする)
ナビゲーションに移動 検索に移動

概要

Qtにおいて、QTimerクラスを使用して、様々な処理を実行する手順を記載する。


タイマイベントの使用例

以下の例では、ダイアログを開いて画像を表示している。
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();
 }