Version 3
タイマー
Version 4
|
はじめにここでは,簡単な例を示し,Qtの特徴であるシグナルとスロットについて簡単に説明してsする.また,ヘッダーファイルの書き方なども説明する.例としてはカップラーメンタイマーを作成する. ここでのサンプルプログラムは「Qt GUIプログラミング」を参考にしている. スピンボックスとスライダーQtにはGUIのための様々なクラスが用意されている.その例として,QSpinBoxとQSliderを紹介する.これらは,QWidgetを継承している.継承しているということは,QWidgetと同じように扱え,さらに便利な機能が付いている.ということである. さて,QSpinBoxとQSliderを表示させるようなプログラムを作ろうと思うが,このふたつの親になるメインのウィジェットも必要になる.ここでは,メインウィジェットをQHBoxにする. このQHBoxは水平方向に子となるウィジェットを並べてくれる便利なものである.(ちなみに垂直方向に並べるQVBoxもある) QHBoxもQWidgetを継承している. それでは,プログラムを実際に作ってみよう.QHBoxを使うためにはqhbox.hをインクルードしなければいけない.同じように,QSpinBoxはqspinbox.hを,QSliderはqslider.hをインクルードしなければ使えない.以下に,プログラムを示す. #include <qapplication.h> #include <qhbox.h> #include <qslider.h> #include <qspinbox.h> int main(int argc, char* argv[]) { QApplication app(argc, argv); QHBox* hbox = new QHBox(0); hbox->setMargin(5); //マージンの設定 hbox->setSpacing(5); //ウィジェット間のスペース QSpinBox* spinBox = new QSpinBox(hbox); //hboxを親とするスピンボックス QSlider* slider = new QSlider(Qt::Horizontal, hbox); //hboxを親とする水平方向のスライダー spinBox->setRange(0, 300); //スピンボックスの値の設定 0から300まで slider->setRange(0, 300); //スライダーの値の設定 0から300まで app.setMainWidget(hbox); hbox->show(); return app.exec(); } コンパイルは,以下のようにする. $ qmake -project $ qmake $ make とコンパイルすればアプリケーションができある. さらに,これを改良してスピンボックスとスライダーの値を結びつけよう.つまり,スピンボックスで値を変えればスライダーの位置が変わり,スライダーの位置を変えればスピンボックスの値が変わるようにする.このためには,シグナルとスロットを使わなければいけない. QSpinBoxにはvalueChanged(int)というシグナルがある.これはQSpinBoxの値が変わったときに発せられるシグナルであり,QSpinBoxの値も送られる.また,QSliderにはsetValue(int)というスロットがある.これは,QSliderの値を設定するスロットである.これらを結びつけるためには QObject::connect(spinBox, SIGNAL(valueChanged(int)), slider, SLOT(setValue(int))); とすればよい.これでspinBoxの値が変わったときにsliderの値が変わるようになる.同じように,sliderの値が変わったときにspinBoxの値が変わるようにするには, QObject::connect(slider, SIGNAL(valueChanged(int)), spinBox, SLOT(setValue(int))); とする. これらを付け足したプログラムを以下に示す. #include <qapplication.h> #include <qhbox.h> #include <qslider.h> #include <qspinbox.h> int main(int argc, char* argv[]) { QApplication app(argc, argv); QHBox* hbox = new QHBox(0); hbox->setMargin(5); //マージンの設定 hbox->setSpacing(5); //ウィジェット間のスペース QSpinBox* spinBox = new QSpinBox(hbox); //hboxを親とするスピンボックス QSlider* slider = new QSlider(Qt::Horizontal, hbox); //hboxを親とする水平方向のスライダー spinBox->setRange(0, 300); //スピンボックスの値の設定 0から300まで slider->setRange(0, 300); //スライダーの値の設定 0から300まで //スピンボックスとスライダーの値を結びつける QObject::connect(spinBox, SIGNAL(valueChanged(int)), slider, SLOT(setValue(int)) ); QObject::connect(slider, SIGNAL(valueChanged(int)), spinBox, SLOT(setValue(int)) ); app.setMainWidget(hbox); hbox->show(); return app.exec(); } クラスにまとめる今作ったプログラムをクラスを使って書き直してみる.作成するクラスはTimerという名前にし,QVBoxを継承させる.するとこのプログラムは次のようになる. #include <qapplication.h> #include <qvbox.h> #include <qhbox.h> #include <qslider.h> #include <qspinbox.h> class Timer : public QVBox{ public: Timer(); //コンストラクタ private: QHBox* hbox; QSpinBox *spinBox; QSlider *slider; }; Timer::Timer() { setCaption("Timer"); //このクラスにタイトルをつける setMargin(5); //このクラス自身のマージンの設定 setSpacing(5); //このクラス自身のウィジェット間のスペース hbox = new QHBox(this); //このクラスを親に持つQHBox hbox->setSpacing(5); //ウィジェット間のスペース spinBox = new QSpinBox(hbox); //hboxを親とするスピンボックス slider = new QSlider(Qt::Horizontal, hbox); //hboxを親とする水平方向のスライダー spinBox->setRange(0, 300); //スピンボックスの値の設定 0から300まで slider->setRange(0, 300); //スライダーの値の設定 0から300まで //スピンボックスとスライダーの値を結びつける QObject::connect(spinBox, SIGNAL(valueChanged(int)), slider, SLOT(setValue(int)) ); QObject::connect(slider, SIGNAL(valueChanged(int)), spinBox, SLOT(setValue(int)) ); } int main(int argc, char* argv[]) { QApplication app(argc, argv); Timer* timer = new Timer(); app.setMainWidget(timer); timer->show(); return app.exec(); } このままでもプログラムは動くが,普通はプログラムを一つのファイルに書くのではなく,複数のファイルに分割して書く.一つのクラスを一つのファイルに書き込むのが通例であるようだ. まず,Timerクラスのヘッダーファイルtimer.hは次のようにする. #ifndef TIMER_H #define TIMER_H #include <qvbox.h> #include <qhbox.h> #include <qslider.h> #include <qspinbox.h> class Timer : public QVBox{ public: Timer(); //コンストラクタ private: QHBox* hbox; QSpinBox *spinBox; QSlider *slider; }; #endif //TIMER_H このヘッダーファイルはほかのファイルでインクルードされる.ヘッダーファイル中の
#ifndef TIMER_H
#define TIMER_H
・
・
・
#endif //TIMER_H
はヘッダーファイルを2回以上インクルードしないための典型的なc言語の手法である. Timerクラスのメンバー関数を書き込むファイルtimer.cppは次のようになる. #include <qvbox.h> #include <qhbox.h> #include <qslider.h> #include <qspinbox.h> #include "timer.h" Timer::Timer() { setCaption("Timer"); //このクラスにタイトルをつける setMargin(5); //このクラス自身のマージンの設定 setSpacing(5); //このクラス自身のウィジェット間のスペース hbox = new QHBox(this); //このクラスを親に持つQHBox hbox->setSpacing(5); //ウィジェット間のスペース spinBox = new QSpinBox(hbox); //hboxを親とするスピンボックス slider = new QSlider(Qt::Horizontal, hbox); //hboxを親とする水平方向のスライダー spinBox->setRange(0, 300); //スピンボックスの値の設定 0から300まで slider->setRange(0, 300); //スライダーの値の設定 0から300まで //スピンボックスとスライダーの値を結びつける QObject::connect(spinBox, SIGNAL(valueChanged(int)), slider, SLOT(setValue(int)) ); QObject::connect(slider, SIGNAL(valueChanged(int)), spinBox, SLOT(setValue(int)) ); } 今の場合は,ファイルの中身はコンストラクタだけである. main関数のファイルmain.cppは次のようにする. #include <qapplication.h> #include "timer.h" int main(int argc, char* argv[]) { QApplication app(argc, argv); Timer* timer = new Timer(); app.setMainWidget(timer); timer->show(); return app.exec(); } このように分割してプログラムを作ってもコンパイル方法は変わらず,以下のようにする. $ qmake -project $ qmake $ make 機能を追加するタイマーとして使うにはもっと機能を追加していかなければいけない.まずはデジタル表示で数字を表示するQLCDNumberを追加する.このためにはTimerクラスのメンバーに QLCDNumber *lcd; を追加して,Timerクラスのコンストラクタに, lcd = new QLCDNumber( 3, this, "lcd" ); lcd->setSegmentStyle(lcd->Filled); を追加する.また,QLCDNumberの表示をスライダーやスピンボックスと結びつけるため connect( slider, SIGNAL(valueChanged(int)), lcd, SLOT(display(int)) ); を追加する. さらにスタートとストップのプッシュボタンも付けたいので,Timerクラスのメンバーに QPushButton *start; QPushButton *stop; を追加し,Timerクラスのコンストラクタに, start = new QPushButton("Start", this); stop = new QPushButton("Stop", this); を追加する.これで見た目は少しはタイマーっぽくなった. シグナルとスロットを設定するQtでは自分でシグナルとスロットを設定することができる.ここではスタートボタンを押せばタイマーがスタートして0までカウントするような機能を持たせる. まずは時間をカウントする仕組みが必要になるがこれにはQTimeクラスを使う.QTimeは時間を設定すると,その時間がくればQtimeout()というシグナルを発してくれる便利なクラスである. 例えば, QTime* time(0); time->start(n*1000, true); とすれば,n秒後に一度だけシグナルを発してくれる.二つ目の引数をfalseにするとn秒毎にシグナルを発してくれる. では独自のスロットを作っていこう.独自のスロットとシグナルを使うためにはクラス宣言の先頭でQ_OBJECTを宣言しなければならない.つまり, class Timer : public QVBox{ Q_OBJECT … … }; と書く.そしてtimer_start()というスロットを作りたければ, class Timer : public QVBox{ Q_OBJECT … … private slots: void timer_start(); }; とする.そして,timer_start()の実装はtimer.cppに書く. この完成したプログラムは,以下の通り. 001 #ifndef TIMER_H 002 #define TIMER_H 003 004 #include <qvbox.h> 005 #include <qhbox.h> 006 #include <qslider.h> 007 #include <qspinbox.h> 008 #include <qlcdnumber.h> 009 #include <qpushbutton.h> 010 #include <qtimer.h> 011 012 class Timer : public QVBox{ 013 Q_OBJECT 014 015 public: 016 Timer(); //コンストラクタ 017 018 private: 019 QLCDNumber *lcd; 020 QHBox* hbox; 021 QSpinBox *spinBox; 022 QSlider *slider; 023 QPushButton *start; 024 QPushButton *stop; 025 QTimer *time; 026 027 //独自のスロット 028 private slots: 029 void timer_start(); 030 void one_sec(); 031 void timer_stop(); 032 }; 033 034 #endif //TIMER_H 035 001 #include <qvbox.h> 002 #include <qhbox.h> 003 #include <qslider.h> 004 #include <qspinbox.h> 005 #include <qlcdnumber.h> 006 #include <qpushbutton.h> 007 #include <qtimer.h> 008 009 #include "timer.h" 010 011 Timer::Timer() 012 { 013 setCaption("Timer"); //このクラスにタイトルをつける 014 setMargin(5); //このクラス自身のマージンの設定 015 setSpacing(5); //このクラス自身のウィジェット間のスペース 016 017 lcd = new QLCDNumber( 3, this, "lcd" ); //3桁の表示 018 lcd->setSegmentStyle(lcd->Filled); //表示方法 019 020 hbox = new QHBox(this); //このクラスを親に持つQHBox 021 hbox->setSpacing(5); //ウィジェット間のスペース 022 023 spinBox = new QSpinBox(hbox); //hboxを親とするスピンボックス 024 slider = new QSlider(Qt::Horizontal, hbox); //hboxを親とする水平方向のスライダー 025 026 spinBox->setRange(0, 300); //スピンボックスの値の設定 0から300まで 027 slider->setRange(0, 300); //スライダーの値の設定 0から300まで 028 029 start = new QPushButton("Start", this); //スタートボタン 030 stop = new QPushButton("Stop", this); //ストップボタン 031 032 time = new QTimer(this); //タイマー 033 034 //スピンボックスとスライダーの値を結びつける 035 connect(spinBox, SIGNAL(valueChanged(int)), 036 slider, SLOT(setValue(int)) ); 037 connect(slider, SIGNAL(valueChanged(int)), 038 spinBox, SLOT(setValue(int)) ); 039 040 //lcdにスピンボックスとスライダーの値を結びつける 041 connect( slider, SIGNAL(valueChanged(int)), 042 lcd, SLOT(display(int)) ); 043 044 //Timerクラス独自のスロットにコネクトする 045 connect( start, SIGNAL(clicked()), 046 this, SLOT(timer_start()) ); 047 connect( time, SIGNAL(timeout()), 048 this, SLOT(one_sec()) ); 049 connect( stop, SIGNAL(clicked()), 050 this, SLOT(timer_stop()) ); 051 } 052 053 //1秒ごとのカウントをはじめる 054 void Timer::timer_start() 055 { 056 time->start(1000, false); 057 } 058 059 //1秒たったときの処理 060 void Timer::one_sec() 061 { 062 if( lcd->intValue() > 0) 063 lcd->display( lcd->intValue() -1 ); //デジタルカウンタを1減らす 064 else 065 time->stop(); //デジタルカウンタが0のときタイマーを止める 066 } 067 068 //タイマーを止める 069 void Timer::timer_stop() 070 { 071 time->stop(); 072 } 001 #include <qapplication.h> 002 003 #include "timer.h" 004 005 int main(int argc, char* argv[]) 006 { 007 QApplication app(argc, argv); 008 009 Timer* timer = new Timer(); 010 011 app.setMainWidget(timer); 012 timer->show(); 013 014 return app.exec(); 015 016 } |