今日はインクジェットプリンタにムカついた。もうね使ってないんだよ?使ってないのになんでインク空なんだよ!?本日5千円の出費。
プリンタ本体は確かに安い。だけどこれインク乾きすぎ。たかだか半年で全部なくなるって製品としてどうなの?電源切れると同時にインク噴出口の蓋がしまるとかさ、そういう機能を何でつけようとしないわけ?
次は絶対インクジェットプリンタは買わん。モノクロレーザーにする。
はい、それでは今日からマルチスレッドをやっていきます。
今回はQThreadのサブクラス化によるマルチスレッドをやっていきます。(リファレンス)
サンプルはC++ GUI Programming with Qt4 381ページのものを少し改変し、使用します。
そして、いつものようにQtCreaterの使用を前提とします。(QtCreaterなどの使い方は ”Qtをはじめよう" を見てください。)
なお、サンプルコードはincludeの部分は省略しております。動かない場合はまずinclude部を疑ってください。
ではコードを
(custumthread.h)
class CustumThread : public QThread { Q_OBJECT//マクロ public: explicit CustumThread();//コンストラクタ void stop();//スレッドを止める QString messageStr;//スレッドが走っているかの状態メッセージ格納 protected: void run();//スレッドを始める関数(再実装) private: volatile bool stopped;//volatileは処理系の最適化の抑制の意味 };
(custumthread.cpp)
CustumThread::CustumThread()//コンストラクタ { messageStr = "Thread Stop!"; stopped = false; } void CustumThread::run()//QThreadのrunの再実装 { bool first = true; while(!stopped)//スレッドがrun状態ならループという意味 { if(first)//ループの最初の一回だけmessageStrを変更するという意味 { messageStr = "Thread Running!";//run中なら first = false; } } stopped = false; messageStr = "Thread Stop!"; } void CustumThread::stop() { stopped = true;//スレッドをとめるためのフラグを立てる }
はい簡単ですね。コメントのとおりです。run()は再実装です。スレッド開始されると呼び出されます。このrunが終わったときがスレッドの終了した時です。(リファレンス)
これらの実行は以下のコードのようになります。
(mainwindow.h)
namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT//マクロ public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private slots: void on_pushButton_clicked();//スレッド開始ボタン void on_pushButton_2_clicked();//スレッド停止ボタン void on_pushButton_3_clicked();//スレッドの状態表示ボタン private: Ui::MainWindow *ui;//uiにはGUI部品類が記述されている。 CustumThread threadA;//<-----------ここ重要。 };
(mainwindow.cpp)
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)//コンストラクタ { ui->setupUi(this); } MainWindow::~MainWindow()//デストラクタ { delete ui; } void MainWindow::on_pushButton_clicked()//Startボタンクリック { if(!threadA.isRunning())//スレッドが停止しているなら開始 { threadA.start(); } } void MainWindow::on_pushButton_2_clicked()//Stopボタンクリック { if(threadA.isRunning())//スレッドが走ってるなら停止 { threadA.stop(); threadA.wait();//終わるまで待つ } } void MainWindow::on_pushButton_3_clicked()//状態表示ボタンクリック { ui->label->setText(threadA.messageStr);//現在のスレッドの状態をラベルに表示 }
はい簡単ですね。理解に重要なのはヘッダのCustumThread宣言部とボタンクリックシグナルの部分(on_pushButtonの部分)だけです。一つ目のボタンを押すとthreadA.startでスレッドを開始します。二つ目のボタンはもしスレッドが開始されているならばthreadAをとめます。threadA.wait()は確実にスレッドが終わるのを待つために呼び出しています。(リファレンス) 三つ目のボタンはthreadAのフィールドのmessageStr(スレッドの状態の文字列格納)を呼び出し、それをラベルに表示させています。 実行すると以下のようになります。(下図はスタートを押した後に状態表示を押した時の場面です。)
以上です。