プログレスバーをマルチスレッドを用いた実装について最後の記事です。
引き続き作成の目的は、
- スレッド実行中はモーダルダイアログを表示させること。
- モーダルダイアログではプログレスバーを表示し進捗が分かること。
- 実行中のスレッドはダイアログのメンバーにアクセスできること。
- スレッド処理が完了次第、モーダルダイアログを閉じること。
でした。
今回はプログレスバーが表示されるダイアログ(DIALOG2)の実装を確認します。
こちらはスレッド呼び出しなどはないため、簡単な内容になっています。
関連リンク:【MFC】マルチスレッドでプログレスバーを実装しよう その1
関連リンク:【MFC】マルチスレッドでプログレスバーを実装しよう その2
PrgDlg.cpp
最初の記事でOnInitDialog関数、WindowProc関数をそれぞれオーバーロードしました。
OnInitDialog関数で進行状況バーの下限/上限を設定します。
次にWindowProc関数でプログレスバーの現在位置を設定します。
WindowProc関数はダイアログにメッセージが発行されると呼ばれるため、頻繁に呼ばれる関数です。
実際に運用する場合は定期的に呼ばれるような関数を定義するといいかもしれません。
OnInitDialog関数
1 2 3 4 5 6 7 8 9 10 |
BOOL CPrgDlg::OnInitDialog() { CDialog::OnInitDialog(); // TODO: ここに初期化を追加してください m_PrgCtrl.SetRange(0, 10000000); return TRUE; // return TRUE unless you set the focus to a control // 例外 : OCX プロパティ ページは必ず FALSE を返します。 } |
コントロール変数m_PrgCtrl(CProgressCtrl型)のSetRange関数でプログレスバーの下限/上限を設定します。
今回はマジックナンバーで【10,000,000】と記載していますが、定数を利用したり、ファイル走査などであれば総ファイル数を指定するなどが考えられます。
関連リンク:CProgressCtrl クラス | MSDN
関連リンク:CProgressCtrl::SetRange | MSDN
WindowProc関数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
LRESULT CPrgDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { if (m_PrgCtrl.m_hWnd) { int nLower, nUpper; m_PrgCtrl.GetRange(nLower, nUpper); if (nUpper > CProgressThreadDlg::nCount) // プログレスバーの進行状況バーを更新 m_PrgCtrl.SetPos(CProgressThreadDlg::nCount); else // 上限を超えていればダイアログを閉じる PostMessage(WM_CLOSE); } return CDialog::WindowProc(message, wParam, lParam); } |
WindowProc関数ではウィンドウハンドルが作成されていれば、OnInitDialog関数で設定した上限と別スレッドでインクリメントされ続けているカウンター変数を比較し、まだ上限に達していなければ進行状況バーを更新します。
既に上限に達している場合はWM_CLOSEをポストし、ダイアログを閉じるように指示しています。
ウィンドウハンドルが作成されているかどうかの確認をしない場合は、実行時エラーが表示されます。これはWindowProc関数内で比較などをしているためです。
関連リンク:WindowProc 関数 | MSDN
関連リンク:CProgressCtrl::SetPos | MSDN
さて、これでようやく完成です。
実行してみると確かに少しずつプログレスバーがカウンタの値によって増加されているのが分かるかと思います。
問題点
さて、これまでの流れでプログレスバーをマルチスレッドで実装することはできました。
ですが、各所で見られたように問題点も多いです。
- スレッドで実行する処理が、プログレスバーを表示するダイアログ作成前に完了する。
→ 例えば、void ThreadProc(void)を何も処理しないようにするとダイアログ生成よりも早くスレッドが閉じられ意図しない動作になるでしょう。
他にもマジックナンバーを埋め込んでいたり、色々問題点がありました。
こういった点をスマートに解決するためにはやはりVisual C++などの書籍を購入し、セマフォなども含めて学習の必要がありそうです。
まとめ
短いプログラムでしたがスレッドの生成について確認してみました。
今回紹介した方法は【ワーカースレッド】を用いた方法で実装しました。
実際に運用する場合には専用の関数を用意するなど、より堅牢なプログラムを行う必要がありそうです。