ぴぐノート

Good code is its own best documentation.

C/C++ MFC プログラミング言語

【MFC】マルチスレッドでプログレスバーを実装しよう その2

投稿日:

昨日に続き、プログレスバーをマルチスレッドを用いて実装してみましょう。
作成の目的は、

  • スレッド実行中はモーダルダイアログを表示させること。
  • モーダルダイアログではプログレスバーを表示し進捗が分かること。
  • 実行中のスレッドはダイアログのメンバーにアクセスできること。
  • スレッド処理が完了次第、モーダルダイアログを閉じること。

でした。
昨日までで関数宣言などは完了したので、各関数の定義・実装を進めていきます。

関連リンク: 【MFC】マルチスレッドでプログレスバーを実装しよう その1

{プロジェクト名}Dlg.cpp

まずはメインダイアログであるDIALOG1のソースコードを編集していきます。

静的変数 static int nCountの実装

プログレスバーが表示されるダイアログから監視される変数として、

を宣言していました。
静的変数なので実装が必要です。
{プロジェクト名}Dlg.cppファイルの適当な場所に以下の実装を記述します。

クラス名は適宜読み替えてくださいね。

ボタンのイベントハンドラ、OnBnClickedButton1()の実装

次に前回、メインダイアログ(DIALOG1)に追加したボタンのイベントハンドラ、OnBnClickedButton1()の実装を行いましょう。

機能としてはボタンを押下されたらスレッドを開始し、プログレスバーが表示されるダイアログを表示します。

AfxBeginThread()関数がスレッドを開始する関数になります。

関連リンク:AfxBeginThread | MSDN

第6引数まである関数ですが、第3~第6まではデフォルト引数が指定されているので、2つの引数を渡します。

  • 第一引数:別スレッドとして実行される関数のポインタ
    (ワーカースレッドの制御関数)
  • 第二引数:制御関数に渡す引数

第二引数はvoid *型なのでポインタであれば何でも渡すことができます。
今回は制御関数の中でメインダイアログクラスのメンバー関数を呼び出すため、自分自身を引数として渡しています。

5行目 ~ 6行目はダイアログのクラスを宣言し、DoModal()関数を呼び出すことでプログレスバー付きのダイアログ(DIALOG2)を表示させています。
メインダイアログの処理はDIALOG2に移りましたので、DIALOG2のウィンドウを閉じるまではここで処理が止まります

スレッドの処理が完了次第、DIALOG2は終了するように実装するため、処理が戻る8行目に完了を通知するメッセージボックスを表示します。

ワーカースレッドの制御関数
static UINT ThreadProc(LPVOID pParam)

AfxBeginThread()関数から呼び出される、ワーカースレッドの制御関数は以下のように実装します。

まずは、AfxBeginThread()の第二引数に与えたvoid *型を正しい型(今回はダイアログクラスでした)に変換します

関連リンク:reinterpret_cast 演算子 | MSDN
関連リンク:dynamic_cast 演算子 | MSDN

まず、reinterpret_castでポインタ型の変換、dynamic_castで正しいオブジェクトへと変換します。

正しく変換が完了できれば、実際に別スレッドで実行される関数を呼び出します。
基本的には重たい処理やユーザーを待たせたい処理の実行関数になるでしょうか。

実処理を行う関数、void ThreadProc()

この実処理を行う関数は人によってそれぞれ異なるのでどんな内容でも構わないのですが、以下のようにしました。

メンバー変数である、nCount(今回は静的変数ですがメンバー変数であってもアクセス可能です)をインクリメントし、100回に一度、100ミリ秒のスリープを実行します。
nCountが10,000,000に到達した時点でループから抜けて処理が終了、スレッドもほぼ同時に終了となります。

ここまででメインのダイアログの記述は終了です。
長くなってしまったのでプログレスバーが表示されるダイアログクラスの実装は明日行いましょう。

まとめ

スレッドが目にも止まらぬ速度で終わってはスレッドの進行が分からないので無意味なスリープなどを挿入していますが、実際にはファイルの書き出しやローディングなどが実行されることになるでしょうか。

クラスの設計をしっかり行っていればメインのダイアログで処理に必要な変数はできる限り少なくしておくべきですがコントロール変数などを持っているダイアログのメンバーにアクセスできるため、利用しやすいですよね。

スポンサーリンク

スポンサーリンク

-C/C++, MFC, プログラミング言語

執筆者:

関連記事

【MFC入門】メッセージボックスにエラーコードを表示させよう

ライブラリなどを使用していると、戻り値にエラーコードを返す関数は比較的多いです。 GetLastError関数(最新のエラーコードを取得する関数)がライブラリに含まれていることもありますが、そうでない …

【Boost】boost::property_treeの例外処理を考えよう!

ライブラリなどを使用していると、「使い方は大体分かった!使ってみよう!」とすると微妙にはまってしまうことがあります。 前回・前々回でお話しした文字コードもその一つですが今回は例外処理について考えてみま …

Eclipse NeonとCDT/MinGWでC++開発環境を作成しよう!(1)

MFCなどを利用する場合にはほぼVisualStudio一択ですが、簡単なコンソールアプリケーションを作る場合にはEclipseのほうが便利な場合も多いです。 特に「普段はJavaで開発を行っているけ …

【OpenCV】MFCのピクチャーコントロールに描画しよう!

前回、OpenCVを使って画像の回転や二値化などを行って動作確認をしました。 今回はMFCでダイアログベースのアプリケーションを作成し、ピクチャーコントロールにOpenCVで読み込んだ画像を表示させて …

C++のプリプロセッサの復習をしよう その1

C++を勉強していた時期から苦手だったのがプリプロセッサでした。 インクルートガードに#ifndefやら#defineやら#pragma onceやら…。 C++に限った話ではありませんが …