• 締切済み

マウスを動かさないとパラパラ漫画が表示されない

Visual studio 2008 C#で作成しているプログラムの挙動がおかしくなる理由がわからないので、質問させて頂きます。 01、02、03と順に番号を振ってあるフォルダを読み込み、フォルダ内の画像をパラパラ漫画のように続けて表示させる、読み込みと再生を同時に行えるようにスレッドを使用したプログラムを作成しています。 「再生」ボタン押下→フォルダ01内の画像を連続表示→フォルダ02内の画像を連続表示→「次へ」ボタン押下→「再生」ボタン押下→フォルダ03内の画像を連続表示→フォルダ04内の画像を連続表示→「次へ」ボタン押下→「再生」ボタン押下… という風に全ての画像をpicturebox1に表示させていきたいのですが、再生ボタンを押してもpicturebox内に表示されず、何故かマウスを動かすと表示が始まります。 また、パラパラ漫画がガクガクとして滑らかに動かない時も同様に、マウスを動かすとなめらかに表示されます。 ガクガクとして滑らかに動かない時に、マウスを動かさないと、 >> //二回目スライドショーのスレッドを開始 >> thread_show = new Thread(new ThreadStart(threadShow)); の部分で InvalidOperationExeception がハンドルされる事があります。 自分でも調べてみたのですが、マウスを動かすとするすると動く理由が分かりません。読み込みと再生スレッドのタイマがうまく咬み合っていないのかと予想しているのですが…。 アドバイス頂けると嬉しいです。     //開始 private void プログラム開始ToolStripMenuItem_Click(object sender, EventArgs e) { //画像読み込みスレッドを開始 present = 0;//present:現在参照している動画像 directory = directories[show_order[present]];//show_order[]:フォルダの再生順序 thread_read = new Thread(new ThreadStart(read_image));//画像読み込みのスレッドthread_read宣言 thread_read.Start(); //再生ボタンを有効に thread_read.Join(); button2.Enabled = true; } //「再生」ボタンを押したとき private void button2_Click(object sender, EventArgs e) { Thread.Sleep(500); //一回目スライドショーのスレッドを開始 thread_show = new Thread(new ThreadStart(threadShow)); thread_show.Start(); //二回目画像読込の設定 if (present <= douga_num - 1) { directory = directories[show_order[present + 1]]; thread_read_one = new Thread(new ThreadStart(read_one_image)); thread_read_one.Start(); } thread_read_one.Join(); //二回目スライドショーのスレッドを開始 thread_show = new Thread(new ThreadStart(threadShow)); thread_show.Start(); thread_show.Join(); button3.Enabled = true;//「次へ」ボタンの表示 } //「次へ」ボタンを押したとき private void button3_Click(object sender, EventArgs e) { //回答フォームの表示 Form3 form = new Form3(this); form.ShowDialog(); if (form.DialogResult != DialogResult.OK) { return; } button3.Enabled = false; if (present < douga_num - 2 )//全動画像-2よりも参照動画番号が小さかったら { directory = directories[show_order[present+2]]; thread_read_one = new Thread(new ThreadStart(read_one_image)); thread_read_one.Start(); thread_read_one.Join(); } //再生ボタンを有効に if (present < douga_num) { button2.Enabled = true;//再生ボタンを有効に } present = present + 2;//参照している動画番号を2増やす //実験終了 if (present >= douga_num) { //再生ボタンを無効に button2.Enabled = false; } } //画像表示のスレッド private void threadShow() { Stopwatch sw = new Stopwatch(); //リストに入っているファイルの数をfile_numbersに入れる file_numbers = img.Count; pictureBox1.Image = img[0]; //フレーム番号のリセット now_show = 1; //時間計測:開始 sw.Start(); while (now_show < file_numbers) { if (33 <= sw.ElapsedMilliseconds) { //前フレームを消去 img[0].Dispose(); img.RemoveAt(0); //画像を表示 pictureBox1.Image = img[0]; //カウントを進める now_show++; //時間計測再スタート sw.Reset(); sw.Start(); }

みんなの回答

  • hidebun
  • ベストアンサー率50% (92/181)
回答No.2

予想ですが、時間計測・画像指定を担当しているスレッドがCPUを専有して、再描画等を行うUIスレッドが動作不能な状態に陥っているのではないかと思います。 例えば、 pictureBox1.Reflesh(); Sleep(1); などとしてみると、挙動が変わるのではないでしょうか。 マウスを動かすと表示が改善されるのは、時間計測スレッドの専有が、マウス操作を契機にOSによって解放され、UIスレッドに制御が渡るためではないかと思います。 プログラムを見る限り、画像の表示時間がとてもクリティカルな要素に見えるのですが、(33ミリ秒で表示を切り替えることを期待している?)、なぜ画像の読み込みを裏でしながら、表示をするのでしょうか? このような時間制御に繊細なプログラムでは、表示以外の動作は極力行わないようにして、表示処理に専念させてあげないと、時間遅れが簡単に起こります。 最初に2セッション分の画像を読み込んでしまえるなら、そのようにした方が良いと思います。 また、上記のSleep(1)でも、要求は満たされないかもしれません。 高精度に時間制御を行うなら、スレッドの数は可能な限り少なくしましょう。

全文を見る
すると、全ての回答が全文表示されます。
  • hidebun
  • ベストアンサー率50% (92/181)
回答No.1

画像を設定した後、再描画が必要なのでは? #マウスを被せると、その部分のグラフィックが汚れて、再描画が行われている //画像を表示 pictureBox1.Image = img[0]; pictureBox1.Refresh();

Meimei88
質問者

お礼

回答ありがとうございます。 再描画をしていなかったので、アドバイス頂いたように画像表示のループ内にReflesh();を記述したところ、マウスを動かさないと表示されないということはなくなりました。 ただ、二回再生する動画像のうち、最初だけ動きがガクガクとしており、これもマウスを動かすと治る(滑らかに再生される)ようなのですが原因がわかりません。 ループ内ではなく、pictureBox1.Image = img[0];の前にReflesh();の記述を行った時も同様の挙動になったので、Reflesh()が影響している訳では無さそうなのですが…。 引き続き、アドバイスを募集しております。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • c#のメソッドjoinが機能しない

    Microsoft visual C#2005でスレッドを使用したプログラムを行なっているのですが,意図した動作を行えません. 意図する動作は,連番で複数の画像を持つ二つのフォルダ(0,1とします)から画像をリストに読み込み,フォルダ0読み込み→フォルダ0内の画像を順に続けて表示(この間にフォルダ1の読み込み)→3秒置いて→フォルダ1内の画像を順に続けて表示です.     //再生ボタン private void button_Click(object sender, EventArgs e) {       //フォルダ0読込 directory = directories[0]; Read = new Thread(new ThreadStart(read_image)); Read.Start(); if(now_loading == true) { Read.join(); } //フォルダ0表示 Showing1 = new Thread(new ThreadStart(Show)); Showing1.Start(); //フォルダ1読込 directory = directories[1]; Reads = new Thread(new ThreadStart(read_images)); Reads.Start(); }       if(now_showing == true) { Showing1.Join(); } if(now_showing == true) { Reads.Join(); } //フォルダ1表示 Showing2 = new Thread(new ThreadStart(Show)); Showing2.Start(); }     //動画表示 private void Show() { Stopwatch sw = new Stopwatch(); //リストに入っているファイルの数をfile_numbersに入れる file_numbers = img.Count; //1枚目を表示 pictureBox1.Image = img[0]; //フレーム番号のリセット now_show = 1; //時間計測:開始 sw.Start(); while (now_show < file_numbers) { if (33 <= sw.ElapsedMilliseconds)//一枚の表示時間が33ミリ秒以上になったら次の画像を表示 { //前フレームを消去 img[0].Dispose(); img.RemoveAt(0); //画像を表示 pictureBox1.Image = img[0]; //カウントを進める now_show++; //時間計測再スタート sw.Reset(); sw.Start(); } } //時間計測:停止 sw.Stop(); //最終フレームを消去 pictureBox1.Image = null; img[0].Dispose(); img.RemoveAt(0); Thread.Sleep(3000);//3秒待機 } //読込 private void read_images() { int read_numbers = Directory.GetFiles(directory).Length; now_loading = true; for (int i = 0; i < read_numbers; i++) { img.Add(Image.FromFile(String.Format("{0}\\{1:000}.jpg", directory, i))); } now_loading = false; } //初回読込 private void read_image() { now_loading = true; //フォルダ内のファイル数の取得 file_numbers = Directory.GetFiles(directory).Length; //画像ファイルを読み込む img = new List<Image>(); for (int i = 0; i < file_numbers; i++)//ファイル数の数 { img.Add(Image.FromFile(String.Format("{0}\\{1:000}.jpg", directory, i))); } now_loading = false; } joinでスレッドの終了を待つということなので,B表示スレッドを開始する前に A表示スレッド.join を置けばよいと考えたのですが,タイマーを配置して見たところA表示のスレッドのjoinを待つ前にB表示のスレッドが始まってしまっているようです.(Show内の始めと終わりの部分でテキスト表示すると,フォルダ1の再生後にフォルダ0のShowスレッドが終了していました) また,各画像フォルダの再生時間もタイマで図るとほぼ指定した通りなのですが自分の時計で計測すると画像500枚で2秒程度短くなってしまいます. joinを使っている時点で表示スレッドを関数にした方が良いのかもしれませんが,何故思うように動かないのか知りたいです. アドバイス頂けると嬉しいです.

  • C#のnew Thread以下のコード分解

    new Thread以下のコードを分解できますか? ====================== private void button1_Click(object sender,EventArgs e) { new Thread(new ThreadStart(delegate() { AllocConsole(); //開始============== for(uint i = 0;i < 100;++i) { Console.WriteLine("Hello " + i); } FreeConsole(); //終了============== })).Start(); } =================== 以上

  • 一定時間ごとにメッセージを表示するWebアプリ

    ASP.NET(C#)でWebアプリを作成中です。初心者です。 「ボタンを押した後、一定時間ごとにテキストボックスにメッセージを表示する」ということは可能でしょうか? 単純に以下のように記述とすると、10秒後にi=9のときのメッセージのみがテキストボックスに表示されます。 1秒ごとにメッセージを表示するには、逐次的にクライアントへ結果を返す必要があると思うのですが、可能でしょうか? void Button1_click(Object sender, EventArgs e){   for(int i=0; i<10; i++){     TexBox1.Text = "○○";     Thread.Sleep(1000);   } } また、この処理はバックグラウンドで動作させたいと思っています。 スレッド化すれば良いと思い、手始めに以下のようなコードを書いたのですが、テキストボックスには何も表示されません。スレッドからメッセージを表示させるにはどうしたら良いでしょうか? void Button1_click(Object sender, EventArgs e){   Thread t = new Thread(new ThreadStart(Output));   t.Start(); } void Output(){   TexBox1.Text = "○○"; } 以上2点よろしくお願いします。方針やキーワードだけでも教えていただけると助かります。

  • Thread.Abortメソッド後の処理について

    Thread.abortメソッドについて分からないことがあったので,助言が頂けると嬉しいです. Thread.Abort () を発生させると,通常そこでスレッドが終了するということなので,その後のスレッド内の処理はスルーされると思っていたのですが,下記コードですとその後の pictureBox1.Image = null;も実行されている様です. mainでスレッド作成→threadAの停止になると考えていたのですが,delegate内では反映されないのでしょうか? Thread thread_a; //スレッド delegate void Del(); private void main(object sender, EventArgs e) { //スレッドを開始 thread_a = new Thread(new ThreadStart(threadA)); thread_a.Start(); } private void threadA() { new Thread(new ThreadStart(delegate { Invoke((Del)delegate { thread_a.Abort(); //画像を消去する pictureBox1.Image = null; }); })).Start(); }

  • C#で引数を渡して、スレッド用の関数をよびだすには?

    C#でスレッドを使う場合、引数が渡せません。 具体的には、 Thread temp=new Thread(new ThreadStart(message)); temp.Start(); private void message(){ ~} と、なり、ThreadStart(message)の部分で、 ThreadStart(message(mystr))とし、 private void message(string s){} 書くことができないのです。 しかし、関数に、引数を渡せないのは、不便です。 何か、方法は、ないでしょうか。

  • スレッド起動したフォームを正常に終了させる。

    Visual Studio 2005 C#.netです。 クラスからフォームをバックグラウンドスレッド起動して、そのフォームを起動したクラスから正常にフォームを消去させたい(終了)させたいのですが、どうすればいいのでしょうか? 現在、以下のプログラムにて実現していますが、Abortで強制終了させているのでDispose(); も行われていないと思います。 呼び出し側からアクションを起こしてAbortではなく、スレッド側から正常に終了させたいのです。 また、Showメソッドだとフォーム表示が一瞬で終わってしまうのは何故でしょうか? よろしくお願いいたします。 クラス: public class FormDisplayClass { //スレッド private System.Threading.Thread thread; //フォーム private TestForm TF = new TestForm();//フォームは別に存在するとします。 //表示メソッド public void Show() { //スレッド設定 this.thread = new System.Threading.Thread( new System.Threading.ThreadStart(FormShow)); //バックグラウンド this.thread.IsBackground = true; //スタート this.thread.Start(); } /// <summary> /// スレッドを終了させる。 /// </summary> public void Close() { this.thread.Abort(); } /// <summary> /// フォームを表示させる /// </summary> private void FormShow() { this.SWD.ShowDialog();//表示      (Showだと表示を持続できない) this.SWD.Dispose(); } #endregion } 呼び出し側: FormDisplayClass FDC = new FormDisplayClass();    private 表示メソッド { FDC.Show(); }    private 終了メソッド { sw.Close(); } } よろしくお願いします。

  • スレッド

    VC++2008ExpressEditionを使用してプログラムを作成しています。 Windowsフォームアプリケーションを作成し、そこに、TextBoxとButtonを放り込み、ボタンを押すと以下のようなコードが実行されるようにしました。 関数testfuncはhoge::Form1::testfuncという風な場所で定義されています。 logBoxは、Form1のコンストラクタのTODOの部分で作成しています。   public: static System::Windows::Forms::TextBox^ logBox;   void testfunc(){     int i;     for(i=0;i<200;i++){       int t=clock();       while(10>clock()-t);       logBox+=L"aaraeaewa"+i+L"\r\n";       logBox->SelectionStart = logBox->Text->Length;       logBox->ScrollToCaret();     }   }   System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {     button1->Enabled=false;     button1->Text=L"実行中";     button1->Update();     ThreadStart^ trddel=gcnew ThreadStart(this,&hoge::Form1::testfunc);     Thread ^trd=gcnew Thread(trddel);     trd->Start();     button1->Enabled=true;     button1->Text=L"実行";   } この関数をボタンを押して実行すると、testfunc関数の logBox->SelectionStart = logBox->Text->Length; の部分で、 'System.InvalidOperationException' のハンドルされていない例外が System.Windows.Forms.dll で発生しました。 追加情報: 有効ではないスレッド間の操作: コントロールが作成されたスレッド以外のスレッドからコントロール 'logBox' がアクセスされました。 という風なエラーが出ます。 読んだ感じだと、元々のスレッドで作成したコントロールを新しく作ったスレッドからコントロールすることは出来ないって感じのことが書かれているのですが、どの様にすればこれは回避できるようになるのでしょうか?

  • 三目並べのコードについて。ビジュアルベーシック2008

    三目並べのコードについて。ビジュアルベーシック2008 現在三目並べのコードにて苦戦しています。 ×が3つ揃えば勝ち、Oが3つ揃えば勝ち、というメッセージが表示されるコードも完了しました。 しかし引き分け、つまり9つのボタンの内3つ揃わなかった場合、どのようなコードにすればいいでしょう?色々やっているのですが、メッセージボックスすら表示されません。 また、勝ち、や引き分け、のメッセージ表示後、自動的にリセットしたく Private Sub reset()         Button1.Text = "" Button1.Enabled = True Button2.Text = "" Button2.Enabled = True Button3.Text = "" Button3.Enabled = True Button4.Text = "" Button4.Enabled = True Button5.Text = "" Button5.Enabled = True Button6.Text = "" Button6.Enabled = True Button7.Text = "" Button7.Enabled = True Button8.Text = "" Button8.Enabled = True Button9.Text = "" Button9.Enabled = True を Private Sub win() If Button1.Text = "X" And Button2.Text = "X" And Button3.Text = "X" Then MessageBox.Show("You are the winner with X!") Call disablebuttons()        Call reset() ・・・以下続く とCALLで呼び出しているのですが、9つきちんとリセットされてくれず必ず9つのボタンのうち一つだけ窪み(何も表示されない状態)になってしまいます。一体どうすればよいでしょう? また、ボタンにカーソルが触れると色が変わるようにしたいのですが、もしお知恵を貸していただけるようでしたらよろしくお願いいたします。

  • C# スレッド終了の監視について

    お世話になります。 C#2005でプログラムを作成しております。 マルチスレッドでの、スレッドの終了の監視のことでご質問させていただきます。 下記のコードを実行すると、問題なく実行されます。 ------------------------------------------------------------------------------------ private int SetDataTreeView() { Thread RcvSetThread = new Thread(new ThreadStart(this.RcvDataSet)); RcvSetThread.Start(); } delegate void RcvDataSetDelegate(); void RcvDataGridSet() { /* フォーム内のDatagidviewへの値の代入 */ } void RcvDataSet() { Invoke(new RcvDataSetDelegate(RcvDataGridSet)); } ------------------------------------------------------------------------------------ このスレッドの終了を監視したく、下記のコードを追加してデバッグしてみましたが、 スレッドが実行されませんでした。 ------------------------------------------------------------------------------------ int isRcvSearchFlg = 0; private int SetDataTreeView() { Thread RcvSetThread = new Thread(new ThreadStart(this.RcvDataSet)); RcvSetThread.Start(); // スレッドが終了するまで待機する for (; ; ) { if (isRcvSearchFlg == 1) { break; } } } delegate void RcvDataSetDelegate(); void RcvDataGridSet() { /* フォーム内のDatagidviewへの値の代入 */ isRcvSearchFlg = 1; } void RcvDataSet() { Invoke(new RcvDataSetDelegate(RcvDataGridSet)); } ------------------------------------------------------------------------------------ また、以下も試してみましたが、結果は同じでした。 ------------------------------------------------------------------------------------ private int SetDataTreeView() { Thread RcvSetThread = new Thread(new ThreadStart(this.RcvDataSet)); RcvSetThread.Start(); // スレッドが終了するまで待機する RcvSetThread.Join(); } delegate void RcvDataSetDelegate(); void RcvDataGridSet() { /* フォーム内のDatagidviewへの値の代入処理 */ } void RcvDataSet() { Invoke(new RcvDataSetDelegate(RcvDataGridSet)); } ------------------------------------------------------------------------------------ スレッドの終了を監視する方法がわからず困っております。 お手数ですが、ご教授いただきたくよろしくお願い申し上げます。

  • スレッドの中断についての質問

    現在、C#でプログラミングを開発しております。初心者ですので、よろしくお願いします。 public delegate void MyMethod(); private Thread t1=null ; public void btn_Download_Click(object sender, EventArgs e) //Go! {   Thread t1 = new Thread(new ThreadStart(DownloadThread_HTTP));   t1.IsBackground = true; t1.Start(); } public void DownloadThread_HTTP() // download Thread { MyMethod DOWNLOAD_with_HTTP = new MyMethod(this.DOWNLOAD_with_HTTP); this.BeginInvoke(DOWNLOAD_with_HTTP); } public void DOWNLOAD_with_HTTP() { ...... } private void button2_Click(object sender, EventArgs e) //pause button { t1.Join(); } コードは 以上です。コンパイラは大丈夫ですけど、プログラムを実行するときに button2をクリックすると NullReferenceException例外エラーが出ます。t1の値がNullのためっていうことをわかりますけど、どうやれば t1の値がNullにならないのですか? ご教授ください、お願いいたします。