• 締切済み

プログレスバーの再描画について

現在,画像データの変換ソフトを作っており,変換計算中に,変換されたファイルの経過状態を示すためにプログレスバーをつけております. プログレスバーは,経過状態に合わせて正常に動作するのですが,別のウィンドウ等に切り替えたりした時にプログレスバーの動作が止まってしまい,変換が終了したときにプログレスバーの終了状態だけが表示されてしまいます. そこで,質問なのですが,どのようにしたらウィンドウを切り替えたときなどにもプログレスバーが再描画されるでしょうか? 現在,変換計算とプログレスバーを別スレッドにはしていないのですがそれが原因なのでしょうか. 現在の環境はWindowsXP VisualC++6.0です. ご教授お願いいたします.

みんなの回答

  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.2

>Keisan()とMyThread()が同時に処理されると思ったのですが 実行環境が「マルチコアCPU」ではない場合、Keisan()とMyThread()は「1つのCPUが順に実行」します。複数のスレッドは同時には処理されません。 「複数のスレッドが時分割で高速に切り替わり、まるで同時に処理されているように見えるだけ」です。 しかも「複数のスレッドが時分割で高速に切り替わ」る為には「カーネルによりスレッドの切り替えが行われる必要」があります。 「カーネルによるスレッド切り替え」を発生させるには「API関数を呼ぶか、イベントハンドラ関数からリターンするなどで、制御がカーネルに移る」必要があります。 >Sleep(100); Sleepは「プロセス全体」を停止させます。そして、この関数を呼んでもカーネルには制御が移らずスレッド切り替えは発生しません。 「単にSleep(100)を10回繰り返す」だけではカーネルに制御が渡らないのでスレッドは切り替わらず、Keisan()スレッドがCPUを占有します。 Windowsでは、このような「特定の関数内でループして長時間CPUを独占し、なかなか関数から抜けない」という書き方をすると、他のスレッド、他のプロセス、他のアプリが沈黙してしまう場合があります。 「動いているCPUは1つだけ」なので、誰かが一人占めすると、他は「後回し」にされてしまいます。 長時間のループを行う場合は、ループの途中で、他のスレッド、他のタスク、他のプロセスに制御を渡し、CPUを占有してはいけません。

fujtomo
質問者

お礼

>長時間のループを行う場合は、ループの途中で、他のスレッド、他のタスク、他のプロセスに制御を渡し、CPUを占有してはいけません。 なるほどですね. ということは,「何かの計算処理をして,その経過時間をプログレスバーに表示させる」というプログラムを作るとして, 一つのスレッドで, ////計算のプログラム///////////////// 計算 ・ ・ ・ プログレスバーに描画 ///////////////////////////////////// とするのと,マルチスレッドにして ///メイン関数////////////////// AfxBeginThread(・・・・) //ワーカースレッドを作成 ・ ・ ・ プログレスバーを描画する /////////////////////////////////// //ワーカースレッド(計算のプログラム)///// 計算 ・ ・ ・ メインに戻す /////////////////////////////////////// では,結果は同じですけどワーカースレッドで計算中に, 一度メインのスレッドに戻ることで長時間CPUを占有させないよう にしているということでしょうか? 何度もお聞きしてすみません.もし,検討違いでしたら申し訳 ないです..

  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.1

・その1 適当なタイミング(10000ピクセル処理ごと、とか、プログレスバーのプロパティ変更時、など)でPumpMessageを呼ぶ。 http://msdn.microsoft.com/ja-jp/library/t1tkd768(VS.80).aspx ・その2 変換ルーチンを別スレッドにして、プログレスバーがあるメインスレッドに進捗度をメッセージで送る ともかく「フォームやコントロールを管理しているメインスレッドで、時間のかかる事を処理し続けない」こと。

fujtomo
質問者

お礼

ご回答ありがとうございます!! 計算処理プログラム内で 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と表示されました. マルチスレッドの根本の考え方がおかしいのかも知れませんが,もしよろしければなにかアドバイスを頂ければ今後の参考になります.

関連するQ&A

  • 「VC++6」ウィンドウの再描画

    VC++6を使って簡単なプログラムをダイアログベース作っています。 内容はリストを読み込み、1件ずつDBにSQLを発行して情報を取得していくという内容です。 画面には、プログレスバーも設置しており、普通に操作すると正常に、プログレスバーも動きます。しかし、いったん別のウィンドウをアクティブにして、作成した動作中のプログラムを再選択しても、画面は壊れたまま再描画されません。しばらくまって、リストのSQL発行が終わって、画面に結果が表示されたら、きちんと再描画されます。 そこまで処理が終わったら、他のウィンドウに切り替えて戻ってきても画面が壊れることはありません。 時間がかかるプログラムなので、動作中に別の仕事をするため、アクティブでなくても、きちんとウィンドウを更新したいのです。 ちなみに、ループ処理中にRedrawWindow();を入れてみましたがダメでした。 アドバイスよろしくお願いします。

  • プログレスバーでの経過状況表示

    vb.netでのtimerのようなものをやりたくてvbaでプログレスバーを使用して経過状況を表示するプログラムを作りました。プログレスバー自体での視覚的な経過状況表示はできたのですが、現在のパーセンテージをlabelに表示することができません。 Private Sub CommandButton4_Click() Dim i As Long Application.Visible = False i = 1 For i = i To 1000000 UserForm1.ProgressBar1.Value = i / 1000000*100 UserForm1.Label1.Caption =UserForm1.ProgressBar1.Value i = i + 1E-44 Next Application.Visible = True End Sub 上記のようにするとプログラム終了時にlabel1に現在のプログレスバーの値が表示されますが、進行中には表示されないのです。これを進行中も表示させるにはどうしたら良いのでしょうか?

  • Javaアプレットで描画の中断がしたい

    Java初心者です。学校の課題で数学シュミレーションの結果を Javaアプレットで表示するプログラムを作成しています。 この課題のJavaアプレットでは 複素平面のシュミレーション(計算結果を色のグラデーションで表示する)なのですが、 チョイスやボタン、マウスクリックなどによって、 初期条件や、描画方式、表示範囲などを指定することができます。 とりあえず、シュミレーション結果の描画は 試行錯誤の結果表示ができるようになりました。 paint(Graphics g)メソッドで数値計算、及び描画をしています。 (ちなみに余談かもしれませんがダブルバッファリングをしていて、 描画内容をImageとして書き込んでおいて描画するというかたちです。) 「計算途中(計算には結構時間がかかる)に 新たにボタンなどで指定条件が変更された場合、 現在の描画を中断して次の計算と描画を開始できるように プログラムを改良しなさい」というのが今回の課題です。 つまり、「プログラム的にはpaintメソッドが実行されている途中に 特定のイベントが発生したらpaintメソッドを中断し、 もういちど呼びなおしなさい」ということかと思われます。 スレッドを作り、そのスレッドを中断するなども考えました。 インターネットで検索もしてみましたが、 なかなか情報を見つけられず困っています。 学生が作るプログラムなのでそんなに難しいことではないのだと思うのですが 解決できませんでした。 どうぞよろしくお願いします。

  • photoshopの描画の表示がおかしくなってしまいました

    photoshopの描画の表示が、添付の画像のようにおかしくなってしまいました。 ナビゲータウィンドウも変になっています。 photoshopはOSをインストールしたときに一緒に入れて、最近までは正常でした。 ブラシでの描画はほぼ別ソフトでしていたため、描画の異常に気がついたのは昨日です。 再インストールをしてみても変わりません。 バージョンは6とエレメンツ2を持っていて、両方とも同じ症状が出ています。 他のグラフィックソフト(SAI、Painter、pixia、openCanvas)は皆正常です。 原因と対処法に心当たりがありましたら、アドバイスをいただけないでしょうか? よろしくお願いいたします。

  • ウインドウ描画のタイミングの制御について

    OpenGLで描画した結果を,自分で指定した時間だけ遅らせて ウインドウに提示したいと考えております. ※たとえば,入力して,10msec経過してから,ディスプレイを描画するなど ご助言を頂けますと幸いです. [現在試している環境]: C++,GLUT GLUTで指定する描画関数 glutDisplayFunc(display);  待機命令: Sleep関数 [試したこと] GLUTで指定した描画関数displyの中で,待機命令を与えました. 処理時間を計測した結果,待機命令分,必ずしも遅れていないことがわかりました. ※例えば,Sleep(10)という記述をdisplay関数内に書いても,10msec遅れない,1,2msec程度しか遅れが発生しない.しかし,Sleep(50)というように待機時間を増やすと,大体49msec程度遅れる. GLUTはdisplay関数は,必ずしも描画される保証はないと,友人に言われましたが, どのようにすれば,任意に画面描画タイミングを決められるのでしょうか? OpenGLを使用して,画面描画タイミングを任意に設定できないものなのでしょうか? ゲームやグラフィックカード等では,やっているような気がしますので方法はありそうなのですが 検討がついていない状態です. 不勉強で申し訳ありませんが,ご助言を頂けませんでしょうか? どうぞよろしくお願いいたします.

  • Delphiのスレッドプログラミング

    ゲームプログラムなんですが、計算するルーチンと描画を行うルーチンの二部構成で現在プログラムを作っています。計算は随時行い、描画は余裕があるときに行うというやり方で、最大限のフレームレートを出そうとしています。 で、いままで、Application.onIdleを使って画面描画していたものを、スレッドを使ってみることにしました。メインスレッドで計算を行い、サブスレッドで描画を行うという方法を考えたのですが・・・。 onIdleを使っているうちは、描画が忙しくなってくる→onIdleが発生しなくなる→描画を間引く→負荷が減るといった構図で丁度よかったのですが・・・。 ---------(描画を行うサブスレッド)--------- While(true) do begin   Start := TimeGetTime;   Synchronize(); // ここでメインスレッド経由でVCLに描画   Stop := TimeGetTime;   If (Stop - Start < 33) then Sleep(33 - stop - start); // 描画が33ms以下で済めば、30FPSになるようにwaitを入れる end; ---------------------------------------- このような方法で最大30FPSを確保しようとしたのですが、描画に負荷がかかってくると、メインスレッドにあるタイマが遅延してしまい、全体がガタガタになってしまいました。OnIdle使用時は描画よりメインの数値計算が優先されていたので、問題なかったのですが・・・。 根本的にマズいんでしょうか、コレ・・・。

  • ウィンドウの描画がモタつきます

    下記の環境でウィンドウ移動時などに描画がモタついて悩んでおります。 OS:WindowsXP SP2 PC:DELL SC440 video: ATI X1550 具体的な症状としては、CPUの負荷が20%前後でも時々、ウィンドウを 移動しようとした時にマウスにウィンドウがついてこない時があります。 マウスで引っ張るとウィンドウがおきざりになり、固まったような 感じになります。そして2,3秒してから急にガクガクとまとめて 移動するような感じになる時があり、困っています。 CPUの負荷が高い時ならこういう感じになるのはよくあることだと 思いますが、現在は負荷が軽くても症状が発生します。

  • 再描画の一般的な方法

    再描画の一般的な方法を教えてください。 セレクトボックスとテキストボックスが2つずつ。 □■□□ 2番が選択されています □□□■ 4番が選択されています こんな窓が、別窓に隠れてから復活して再描画する場合、 case WM_PAINT: でセレクトボックスのチェック状態を 調べるのはよくなく、再描画のために、フラグを用意して、 セレクトボックスに変化があった場合はフラグを書き替えて、 テキストボックスの描画はフラグの値を参照した方がいいと 思いました。 この例の場合はセレクトボックスを調べるだけだから セレクトボックスを調べてもいいと思うけど、もっと複雑な計算をしたり 大きなファイルを読み込ませた結果でテキストボックスの値が決まる場合の ことを考えたら、フラグを用意するのがいいと思いました。 でも、セレクトボックスとテキストボックスがもっとたくさんあったり した場合には、フラグの数が多くなるから、フラグを参照するより、 再描画のために、表示に変化があった場合には、窓のクライアント全体を メモリに保存しておいて、再描画ではメモリから表示した方がいいとも 思いました。 たくさんの種類のセレクトボックスとか文字とかがある窓は 普通はどんな風に再描画させているんですか?

  • 重いグラフィックス処理

    Windows VisualC++/MFC でのご質問です。 大きなグラフィックスデータをSDIアプリケーションで表示しているのですが、データが重く描画に10数秒時間を要してしまいます。1mil1画素といった具合に割り当てているのですが、あまりにも重過ぎます。描画を早くしたいのですが、何か良い手はありますでしょうか? 現在はDCに直接描画しています。メモリDCも試しましたが、サイズが大きすぎてbitmapが作れまずあきらめました。 以上、ご指導よろしくお願いします。

  • リアルタイムにhtmlソースが描画されるブラウザはないでしょうか

    リアルタイムにhtmlソースが描画されるブラウザはないでしょうか 具体的に説明しますと、ブラウザでページを表示している状態で そのページのhtmlソースも別ウインドウで表示され、 ページを遷移した際は、htmlソースウインドウの表示も遷移先ページの ソース内容に更新される、といったようなものをイメージしています。 意味不明でしたら加筆修正しますのでよろしくお願いします。

    • ベストアンサー
    • HTML

専門家に質問してみよう