• ベストアンサー

[C#.net]スレッド化された別フォームのプログレスバーの操作方法について

こんちは。最近C#をやり始めて行き詰まったので質問致します。 質問内容に対する答えをお持ちの方がいらっしゃいましたら、お暇な時にでもお答えください。 public Class SumLoop { public Keisan(int Cnt, string Msg) {   // (1)プログレスバーのフォーム生成時に変数Cntをプログレスバーの最大値、変数Msgをフォームのタイトルに設定したい。   FormProgress FrmPro = new FormProgress();  Thread thread = new Thread(new ThreadStart((2)) );   thread.Start();   for(int i=0; i<Cnt; i++) {   // (3)このiがインクリメントする度にプログレスバーのValueを増やしたい   // FrmPro.SetProgressValue(i) // これだとコンパイラに怒られた    // ここに主な処理   } } public partial class FormProgress : System.Windows.Forms.Form {  public FormDfmProgress() { InitializeComponent(); }  // (3)これではダメみたい  public void SetprogressValue(int iValue) {   progressBar1.Value = iValue;   progressBar1.Refresh();  }  // (4)他のイベントが必要? } ざっと汚いコードを書きましたが具体的にお知恵を貸して頂きたいところは (1)のフォーム生成時のパラメータをどう与えるのか? インスタンス作成の際にここで言うFormDfmProgressをthisで継承させオーバーロードさせれば良いんでしょうか? (2)プログレスバーのフォームを表示させたいだけなのですが、.ShowDialog()では怒られ、.Showでは即座にフォームが消えたりでどうにもなりません。スレッドが消えるまで表示させるにはどうしたらいいでしょう? (3)フォーム側のプログレスバーのValueなり、変数なりをスレッド稼動中に更新させるにはどうしたらいいでしょうか? (4)は、大して気にしていないのですが、これが致命的に足りない!とかいうのがあればご指導願います。 以上長々となりましたが、お暇な方お力を御貸しください

質問者が選んだベストアンサー

  • ベストアンサー
noname#259269
noname#259269
回答No.3

>Keisanメソッドが言わばMainのような形で、フォームやらその他のメソッドは常にKeisanメソッドの従としたいのでした。 フォームに貼り付いたコントロールには、プライマリスレッドからしかアクセスできないのですよ。だから、redfox63 さんのような回答になる訳です。

mindatg
質問者

お礼

なるほど、コントロールにはそんな制約があったんですか。 初めて知りました。どおりでそんな感じの解説やサンプルコードが見つからなかった訳か、と恥ずかしい余りです。 ありがとうございました。

その他の回答 (2)

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.2

この部分は スレッド作成するイベント側で記述します Thread thread = new Thread(new ThreadStart((2)) ); thread.Start(); (2)はデリゲートを指定しますので 引数なしのデリゲート用関数を用意します FormProgressのキャプション(タイトル)の変更は Textプロパティでできます Public Class SumLoop {   public int nCnt = 0;   public String sMsg = "";   public void keisan()   {     FromProgress frm = new FormProgress();     frm.Text = sMsg;     frm.setProgrssMax( nCnt );     frm.Show();     for( int i = 0; i < nCnt; i++ ) {       frm.setProgressValue( i );       Thread.Sleep( 10 );     }   } } ProgessBarの最大値は Maximumプロパティを操作するので 外部から扱えるようにメソッドを追加しましょう public void setProgressMax( int nMax ) {   progressBar1.Maximum = nMax; } スレッド起動側のイベントで SumLoop objSL = new SumLoop(); objSL.nCnt = 200; objSL.sMsg = "タイトル"; Thread thread = new Thread( new ThreadStart( objSL.Keisan ) ); thread.Start(); といった具合でしょう

mindatg
質問者

お礼

わざわざコードまで付けて頂いて恐縮です。 ただ、こちらの方法では計算(Keisanメソッド)をスレッド化するようです。 私のコードと質問内容の書き方が悪いといえばそれまでですが Keisanメソッドが言わばMainのような形で、フォームやらその他のメソッドは常にKeisanメソッドの従としたいのでした。 後学の参考とさせて頂きます。

noname#259269
noname#259269
回答No.1

こういうときには、BackgroundWorker という便利なものがありますので、そちらを使いましょう。 http://www.atmarkit.co.jp/fdotnet/dotnettips/436bgworker/bgworker.html http://msdn.microsoft.com/ja-jp/library/system.componentmodel.backgroundworker(VS.80).aspx

mindatg
質問者

お礼

ご意見ありがとうございます、不思議なことにリンクが紫色でした。 ただ、今回教えて頂きたい事とはちょっと違うようです。

関連するQ&A

  • c# スレッド間でのデータの共有

    C#でメインプロセスと生成されたスレッド間でデータの共有をさせたいのですがどのようにすればいいのでしょうか。ご教授お願い致します。 ・メインプロセス(A) ・Aから生成されたスレッド(B) 例えば、AとBで変数の値をそれぞれ読み書きさせたい場合 どのようにすればよいのでしょうか。 class TEST { public int flag; // メインプロセス(A) public static void Main() { Thread t = new Thread(new ThreadStart(abc)); t.IsBackground = true; t.Start(); while(ture) { Thread.Sleep(10); Console.WriteLine("A:{0}",flag); } } // Aから生成されたスレッド(B) public void abc() { Console.WriteLine("B:{0}",flag); flag++; } }

  • C# プログレスバーに関すること

    先ほどご質問させて頂いた件で1つ解決していなかったのですが質問のほうを閉じてしまいました. なので,もう一度ご質問させて頂きます. ic += 1; //プログレスバーの設定 //最小値 int minimum = 0; //最大値 int years = iYearE - iYearS; int hours = iHourE-iHourS; int iiMinute = iiMinuteE-iiMinuteS; int Maximun = (years+1) * Maxmonth * Maxday * (hours+1) * (iiMinute+1); progressBar1.Style = ProgressBarStyle.Continuous; progressBar1.Minimum = minimum; progressBar1.Maximum = Maximun; progressBar1.Value = ic; label8.Text = (ic / Maximun)*100 + "%処理中"; if (ic/Maximun==1) { label8.Text = "終了"; 上記の様なプログラムを組んでプログレスバーを表示させているのですが,問題はラベルの中が 変動せずに,プログラスバーがすべてたまるまで0%で,たまった瞬間に100%になってしまいます. どうすればラベルのほうの数値を徐々に大きくしていけるのでしょうか? どなたかご教示お願いたします. }

  • 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# or VB プログレスバー

    プログレスバーで進行状況を表示する処理を入れています。 http://dobon.net/vb/dotnet/programing/progressdialog.html 上記のサイトをパクってとりあえず作ってみました。きちんとできているのですが 1つだけ問題があって try { ProgressDialog pd = new ProgressDialog(); //ダイアログのタイトルを設定 pd.Title = "カウントアップ"; //プログレスバーの最小値を設定 pd.Minimum = 0; //プログレスバーの最大値を設定 pd.Maximum = 10; //プログレスバーの初期値を設定 pd.Value = 0; //進行状況ダイアログを表示する pd.Show(this); //処理を開始 for (int i = 1; i <= 10; i++) { //プログレスバーの値を変更する pd.Value = i; //メッセージを変更する pd.Message = i.ToString() + "番目を処理中..."; //キャンセルされた時はループを抜ける if (pd.Canceled) break; //1秒間待機する(本来なら何らかの処理を行う) System.Threading.Thread.Sleep(1000); } //ダイアログを閉じる pd.Close(); } catch { MessageBox.Show("error"); } こんな感じで使い、プログレスバー表示中に例外が走るとMessageBoxがモーダレスで 表示されてしまいます。プログレスバー表示前だとモーダルのままです。 色々調べたところ原因は裏でスレッドが走っているからだと思います。たぶん・・ ところが対処法となると少々困っています。モーダルでMessageBoxを表示させたいのですが どうすればよいのでしょうか?教えてください。

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

    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(); } } よろしくお願いします。

  • javaのスレッドの割込みについて

    javaのスレッド割込みに関する初心者の質問です。 割込みの発生元でCNTに値を設定し、割込みの受信元でCNTの値を読込み、表示しています。 下記のコードを参照ください。 Q1)CNTの値の設定と読込みで競合が発生する様なことはありませんか? 又は、処理が停滞するとか 以上、お手数をお掛けしますが、宜しくお願いします。 //割り込を発生するスレッド class threadA extends base{ private Thread target; public threadA(Thread targetA){ target = targetA; } public void run(){ for(int i = 0; i < 8;i++){ try{ System.out.print("."); Thread.sleep(1); CNT=i; target.interrupt(); }catch(InterruptedException e){ System.out.println("今割り込まれました: thread"); } } } } //スレッドからの割り込みを受信するルーチン class Sample108{ public static void main(String args[]){ //for(int i=0; i<2; i++){ classA obj = new classA(); obj.threadStart();//割り込みを受けるルーチン、この中で、割り込みを発生するルーチンを起動している //} } } //割り込みを受けるルーチン class classA extends base{ void threadStart(){ System.out.println("Start: main****"); threadA obj = new threadA(Thread.currentThread()); obj.start(); //Thread起動 //mainのルーチン for(int j = 0;j < 20; j++){ try{ Thread.sleep(1); System.out.print("*"); }catch(InterruptedException e){ System.out.println("今割り込まれました: classA CNT="+CNT); } } } } 以上

    • ベストアンサー
    • Java
  • 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(); } =================== 以上

  • 別クラスのスレッドによるpaint()が上手くいきません!!

    たびたびすみません、、、今度は別のクラスに記述したpaint()をメインでスレッド起動しても描写されません…オーバーライドか何かしなければいけないらしい情報を探し当てた気がするのですが、いまいちよくわかりません。。どうすればいいのでしょうか? 下に自分で作ってみたソースの抜粋を書きます。 import java.awt.*; import java.awt.event.*; class test extends Frame { subclass sc = new subclass(); Thread th=new Thread(sc); public static void main(String args[]) { test t=new test(); } public test() { setTitle("Test"); setSize(300,200); setVisible(true); th.start(); //閉じる addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); } } class subclass extends Frame implements Runnable { int i; public void run() { for(i=0;i<100;i++) { repaint(); } try { Thread.sleep(1000); } catch(InterruptedException e){} } public void paint(Graphics g) { g.drawOval(i,i,50,50); } } (EOS) どうか教えていただける方、お願いします!!

  • C#(VS2013)のWorkerスレッド

    Q1) C#(VS2013)のForm上に配置しました、mouseClick(...)を、Workerスレッドから 割込み起動する方法はありますか? mouseClick(...)とWorkerスレッドに関しましては、下記のコードを参照ください。 ================== private void mouseClick(object sender,MouseEventArgs e) { //これも動作する、1ピクセル単位で描画 Invalidate(); //Invalidate()は、mouseClickルーチンを抜けてからその効力を発行 } public class Worker { // Form1 fm1=new Form1(); int CNT=0; static System.Diagnostics.Stopwatch sw=new System.Diagnostics.Stopwatch(); public void DoWork() { while(!_shouldStop) { //JOB======== while(Form1.flag_DRAWSRT==true && CNT<400) ; //CNT<400必要 //========================= ここに、mouseClick(...)を起動するコードを書きます(その質問です) //========================= //Form1.flag_DRAWSRT=true; //fm1.pictureBox1_drawA(); Thread.Sleep(100); //fm1.OnPaintA(); //=========== if(CNT==0) { sw.Reset(); sw.Start(); } if(CNT>400) { _shouldStop=true; Console.WriteLine("Period[ms]="+sw.Elapsed); } CNT++; } Console.WriteLine("worker thread: terminating gracefully."); } public void RequestStop() { _shouldStop = true; } public void RequestStart() { _shouldStop = false; } // Volatile is used as hint to the compiler that this data // member will be accessed by multiple threads. private volatile bool _shouldStop=false; }//public class Worker { 以上、宜しくお願いします。

  • Visual c# スレッド

    プログラム初心者です。 Visual c#にてスレッド関数を使ったプログラムを見よう見まねで 作りました。 スタートボタンを押すとピクチャーボックスの位置が 左から右へ移動し、ストップボタンを押すと止まる。 ピクチャーボックスの位置をテキストボックスに表示する。 というプログラムのつもりです。 デバックの状態でスタートボタンを押すとエラーメッセージが出て テキストボックスに位置を書き込むの関数のところが緑色にハイライトされます。エラーの内容は「有効でないスレッド間の操作」とありますが、どうしたら良いのか分かりません。 エラーの直し方を教えてください。 プログラムコードは以下です。 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Threading; namespace bit_map_08._1._ { public partial class Form1 : Form { private Thread thread; static private int Position = 0; static private int i; static bool BtnOnFig; public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { thread = new System.Threading.Thread(newSystem.Threading.ThreadStart(MainThread)); thread.Start(); } private void PointMove() { if (i < 300) { i = i + 1; Position = Position + i; textBox1.Text = Convert.ToString(Position); pictureBox1.Left = (Position); } if (i == 300) { i = 0; } } private void MainThread() { while( true ) { Thread.Sleep(100); if (BtnOnFig == true) { PointMove(); } } } private void button1_Click(object sender, EventArgs e) { BtnOnFig = true; } private void button2_Click(object sender, EventArgs e) { BtnOnFig = false; } } }

専門家に質問してみよう