- 締切済み
プログレスバーの再描画について
現在,画像データの変換ソフトを作っており,変換計算中に,変換されたファイルの経過状態を示すためにプログレスバーをつけております. プログレスバーは,経過状態に合わせて正常に動作するのですが,別のウィンドウ等に切り替えたりした時にプログレスバーの動作が止まってしまい,変換が終了したときにプログレスバーの終了状態だけが表示されてしまいます. そこで,質問なのですが,どのようにしたらウィンドウを切り替えたときなどにもプログレスバーが再描画されるでしょうか? 現在,変換計算とプログレスバーを別スレッドにはしていないのですがそれが原因なのでしょうか. 現在の環境はWindowsXP VisualC++6.0です. ご教授お願いいたします.
- みんなの回答 (2)
- 専門家の回答
みんなの回答
- chie65536
- ベストアンサー率41% (2512/6032)
>Keisan()とMyThread()が同時に処理されると思ったのですが 実行環境が「マルチコアCPU」ではない場合、Keisan()とMyThread()は「1つのCPUが順に実行」します。複数のスレッドは同時には処理されません。 「複数のスレッドが時分割で高速に切り替わり、まるで同時に処理されているように見えるだけ」です。 しかも「複数のスレッドが時分割で高速に切り替わ」る為には「カーネルによりスレッドの切り替えが行われる必要」があります。 「カーネルによるスレッド切り替え」を発生させるには「API関数を呼ぶか、イベントハンドラ関数からリターンするなどで、制御がカーネルに移る」必要があります。 >Sleep(100); Sleepは「プロセス全体」を停止させます。そして、この関数を呼んでもカーネルには制御が移らずスレッド切り替えは発生しません。 「単にSleep(100)を10回繰り返す」だけではカーネルに制御が渡らないのでスレッドは切り替わらず、Keisan()スレッドがCPUを占有します。 Windowsでは、このような「特定の関数内でループして長時間CPUを独占し、なかなか関数から抜けない」という書き方をすると、他のスレッド、他のプロセス、他のアプリが沈黙してしまう場合があります。 「動いているCPUは1つだけ」なので、誰かが一人占めすると、他は「後回し」にされてしまいます。 長時間のループを行う場合は、ループの途中で、他のスレッド、他のタスク、他のプロセスに制御を渡し、CPUを占有してはいけません。
- chie65536
- ベストアンサー率41% (2512/6032)
・その1 適当なタイミング(10000ピクセル処理ごと、とか、プログレスバーのプロパティ変更時、など)でPumpMessageを呼ぶ。 http://msdn.microsoft.com/ja-jp/library/t1tkd768(VS.80).aspx ・その2 変換ルーチンを別スレッドにして、プログレスバーがあるメインスレッドに進捗度をメッセージで送る ともかく「フォームやコントロールを管理しているメインスレッドで、時間のかかる事を処理し続けない」こと。
お礼
ご回答ありがとうございます!! 計算処理プログラム内で MSG msg; while (PeekMessage(&msg,0,0,0,PM_REMOVE)){ TranslateMessage(&msg); DispatchMessage(&msg); } のコードをいれることで改善出来ました. ただ,一つ質問があるのですがマルチスレッドのプログラムに挑戦して いて次のようなプログラムを作りました. /////CSampleDlg.h/////////////////////////// class CSampleDlg : public CDialog { public: static UINT ThreadFunc( LPVOID pParam ); void MyThread(); void Keisan(); ・ ・ ・ protected CWinThread* m_pThread; ・ ・ } ////CSampleDlg.cpp////////////////////// BOOL CSampleDlg::OnInitDialog { ・ ・ ・ m_pThread = AfxBeginThread( ThreadFunc, this ); Keisan(); } UINT CSampleDlg::ThreadFunc( LPVOID pParam ) { ((CThreadDemoDlg*)pParam)->MyThread(); return 0; } void CSampleDlg::MyThread() { AfxMessageBox("Hello!!"); } void Keisan() { for(int i=0;i<10;i++){ Sleep(100); } } このようにプログラムを作成すれば,自分の想像ではAfxBeginThreadからスレッドが分かれ,Keisan()とMyThread()が同時に処理されると思ったのですが,デバックしてみるとKeisan()の処理後にMyThread()が処理されています.デバック上でそう見えるだけだと思ったのですが,実際に実行してみても何秒かたってから,Helloと表示されました. マルチスレッドの根本の考え方がおかしいのかも知れませんが,もしよろしければなにかアドバイスを頂ければ今後の参考になります.
お礼
>長時間のループを行う場合は、ループの途中で、他のスレッド、他のタスク、他のプロセスに制御を渡し、CPUを占有してはいけません。 なるほどですね. ということは,「何かの計算処理をして,その経過時間をプログレスバーに表示させる」というプログラムを作るとして, 一つのスレッドで, ////計算のプログラム///////////////// 計算 ・ ・ ・ プログレスバーに描画 ///////////////////////////////////// とするのと,マルチスレッドにして ///メイン関数////////////////// AfxBeginThread(・・・・) //ワーカースレッドを作成 ・ ・ ・ プログレスバーを描画する /////////////////////////////////// //ワーカースレッド(計算のプログラム)///// 計算 ・ ・ ・ メインに戻す /////////////////////////////////////// では,結果は同じですけどワーカースレッドで計算中に, 一度メインのスレッドに戻ることで長時間CPUを占有させないよう にしているということでしょうか? 何度もお聞きしてすみません.もし,検討違いでしたら申し訳 ないです..