今日はインクジェットプリンタにムカついた。もうね使ってないんだよ?使ってないのになんでインク空なんだよ!?本日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(スレッドの状態の文字列格納)を呼び出し、それをラベルに表示させています。 実行すると以下のようになります。(下図はスタートを押した後に状態表示を押した時の場面です。)
以上です。
