C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[4]: 本スレッドが稼働しているときの別スレッドでのボタン操作


(過去ログ 94 を表示中)

[トピック内 5 記事 (1 - 5 表示)]  << 0 >>

■56168 / inTopicNo.1)  本スレッドが稼働しているときの別スレッドでのボタン操作
  
□投稿者/ anny (1回)-(2011/01/02(Sun) 20:33:40)

分類:[C#] 

開発環境
Windows7 
VisualC# 2008

こんにちは,初めて利用させていただきますC#初心者です.
別スレッドを立てても効果的な使い方ができず困っています.以下,実現したいことと現状です.

したいこと
Orig_studentというフォームが表示(Orig_student_Activatedメソッド)されたらhistory_reader_s(マウスで描画した軌跡を表すデータ)から1行ずつ読み取り,
processPacket()というメソッドを使ってOrig_studentフォーム内のピクチャボックスに描画を行う(history_reader_sの内容を再現する描画を行いたい).
stopButtonを押したら描画を停止し,viewButtonを押したら描画を再開したい.

現状
描画とボタン操作は同じスレッド内では無理だと考え,ボタン操作を違うスレッドを立てて行おうと思いましたが,実際は
・processPacket()を用いてピクチャボックスに描画することは可能ですが,stopButtonやviewButtonを用いて描画の停止・再生を行うことができない(描画中に停止・再生ボタンが使用できない).
・描画がすべて終わってから停止・再生ボタンを押すことが可能になる.
となり,スレッドを立てている意味がありません.

別スレッドでボタンとそのイベントハンドラを作成していますが,そのボタンを張り付ける先がOrig_studentフォームだからだめな気がします.
描画中にボタン操作を可能にするにはどうすればいいでしょうか?

描画部分(processPacket())はかなり面倒なことになっているので,ボタン操作のほうを別スレッドで行いたいです.

以下ソースです.
よろしくお願いします.

public partial class Orig_student :Form
{
private void Orig_student_Activated(object sender, EventArgs e)
        {
            if (type == 1) return;
            if (hist_flag == false) return;
	  
	  history_reader_s = new StreamReader(CurrentDir+"\\"+histData_s[0].file);	//読み込みたいファイルのStreamReader作成

            this.newTab_s = new System.Windows.Forms.TabPage();
            this.newTab_s.Size = tabPage01.Size;
            this.tabControl1.TabPages.Add(newTab_s);

            this.newPanel_s = new System.Windows.Forms.Panel();		//再生・停止ボタンを張り付けたいパネルを作成
            this.newPanel_s.Location = panel1.Location;
            this.newPanel_s.Size = panel1.Size;
            this.newPanel_s.BackColor = Color.White;
            this.newTab_s.Controls.Add(newPanel_s);

            Packet pk = new Packet();
            
            HistThread = new Thread(new ThreadStart(MakeButton));		//停止・再生ボタンを利用するスレッド作成
            HistThread.IsBackground = true;
            HistThread.Start();
            while (history_reader_s.Peek() > -1)
            {
                if (stop_flag == false)
                {
                    pk.processPacket(history_reader_s.ReadLine());		//描画
                }
            }
            hist_flag = false;
        }
	private void MakeButton()	//停止・再生ボタンを作成する
        {
            this.stopButton = new System.Windows.Forms.Button();
            this.stopButton.Location = button11.Location;
            this.stopButton.Text = "stop!!!";
            this.stopButton.Size = button11.Size;
            
            this.stopButton.Click += new EventHandler(stopButton_Click);

            this.viewButton = new System.Windows.Forms.Button();
            this.viewButton.Location = button10.Location;
            this.viewButton.Text = "view";
            this.viewButton.Size = button10.Size;
           

            this.viewButton.Click += new EventHandler(viewButton_Click);

            setButton SB = new setButton(Set);		//フォームにボタンを張り付ける
            this.Invoke(SB);

        }

	private void Set()
        {
            this.newPanel_s.Controls.Add(stopButton);
            this.newPanel_s.Controls.Add(viewButton);
            stopButton.BringToFront();
            viewButton.BringToFront();
        }

	private void stopButton_Click(object sender, EventArgs e)
        {
            stop_flag = true;
        }

        private void viewButton_Click(object sender, EventArgs e)
        {
            stop_flag = false;
        }

}

	

引用返信 編集キー/
■56170 / inTopicNo.2)  Re[1]: 本スレッドが稼働しているときの別スレッドでのボタン操作
□投稿者/ Azulean (665回)-(2011/01/02(Sun) 22:26:33)
2011/01/02(Sun) 22:28:13 編集(投稿者)

具体的なことが書かれてあるのは良いことではあるのですが読むのが大変だったりします。
ここから私が書く前提として、きちんとすべてを読んでないことを先に断っておきます。

No56168 (anny さん) に返信
> 別スレッドでボタンとそのイベントハンドラを作成していますが,そのボタンを張り付ける先がOrig_studentフォームだからだめな気がします.
> 描画中にボタン操作を可能にするにはどうすればいいでしょうか?

基本的にできません。
通常、この手のスレッドでループするような処理が必要なのであれば、その処理をワーカースレッドとするか、受信などのイベント受けて処理するイベント駆動にするべきです。


> 描画部分(processPacket())はかなり面倒なことになっているので,ボタン操作のほうを別スレッドで行いたいです.

この前提を崩せないのであれば、基本的にボタン操作を認めることはできない(=アプリがフリーズする)と考えるべきです。
どうしても、どうしても何ともならないのであれば、Application.DoEvents を入れれば少しマシに見えるかもしれませんが、押せてはいけないボタンが押せる、もう一度イベントが発生するなどの弊害発生する可能性があります。

原則として、Application.DoEvents の使用は控えるべきです。
ただ、それに対する processPacket の改修・設計見直しに伴うリスク、今後の保守のリスク、Application.DoEvents を用いることによるリスクの発生確率・影響度が見えていません。これらのリスクを考慮した上で、どうするかご検討ください。


# そもそも、ボタンを動的に作る必要はないのでは?Visible プロパティとか Enabled プロパティとかで何とかなりそうですし。
引用返信 編集キー/
■56172 / inTopicNo.3)  Re[2]: 本スレッドが稼働しているときの別スレッドでのボタン操作
□投稿者/ anny (2回)-(2011/01/02(Sun) 23:05:42)
Azulean様,読みにくいにもかかわらず回答を頂きありがとうございます.

>>別スレッドでボタンとそのイベントハンドラを作成していますが,そのボタンを張り付ける先がOrig_studentフォームだからだめな気がします.
>>描画中にボタン操作を可能にするにはどうすればいいでしょうか?
>
> 基本的にできません。
> 通常、この手のスレッドでループするような処理が必要なのであれば、その処理をワーカースレッドとするか、受信などのイベント受けて処理するイベント駆動にするべきです。

描画部分をワーカースレッドとしていないのには面倒な部分があるという点もありますが,描画するピクチャボックスもフォーム内(メインスレッド)のものなので,別スレッドを立ててもInvoke等で結局メインスレッドにアクセスする必要があり,あまり意味がない気がしました.
そんなことはないのでしょうか?
イベント駆動については勉強不足でよくわからないので少し調べてみます.

> どうしても、どうしても何ともならないのであれば、Application.DoEvents を入れれば少しマシに見えるかもしれませんが、押せてはいけないボタンが押せる、もう一度イベントが発生するなどの弊害発生する可能性があります。

Application.DoEventsというものがあるのですね.初めて知りました.
とりあえず入れてみたところ,何とか思い通りには動くようになりました.
私のプログラムだと現状では問題ないように思えるので,このまましばらく観察したいと思います.

> # そもそも、ボタンを動的に作る必要はないのでは?Visible プロパティとか Enabled プロパティとかで何とかなりそうですし。
別スレッドで作成すれば何とかなるのではないかと考えた悪あがきのためでした.
ご指摘の通り動的に作成する必要はないようです.
引用返信 編集キー/
■56173 / inTopicNo.4)  Re[3]: 本スレッドが稼働しているときの別スレッドでのボタン操作
□投稿者/ Azulean (666回)-(2011/01/03(Mon) 00:01:20)
No56172 (anny さん) に返信
> 描画部分をワーカースレッドとしていないのには面倒な部分があるという点もありますが,
> 描画するピクチャボックスもフォーム内(メインスレッド)のものなので,別スレッドを立ててもInvoke等で
> 結局メインスレッドにアクセスする必要があり,あまり意味がない気がしました.

描画する部分が極端に重いのであれば、そうなるかもしれません。
しかし、そういった場合は Application.DoEvents を使っても似たようなものです。

ワーカースレッドでは受け取ったデータの解析、描画に必要なデータ生成までとし、実際の描画はメインスレッドに Invoke なり、BeginInvoke なりを使うか、Invalidate メソッドを呼ぶだけにして後でくる Paint イベントで描画するかでしょうか。
ただ、スレッド間で同期をうまく取らないと、描画がずれる、データが上書きされるなどの問題が発生する可能性があります。


> イベント駆動については勉強不足でよくわからないので少し調べてみます.

私がイベント駆動といったのは、「データを受け取った」と言ったようなイベントを受けて必要な処理をすることです。
While ループで待つ代わりに、一度処理するごとにイベントハンドラから抜けて、次のイベントを待つ形です。

今回の事例に使えるかどうかまでは調べていません。
(データ受信完了、データ受信可能などのイベントを起こす仕組みがないとできない)
引用返信 編集キー/
■56180 / inTopicNo.5)  Re[4]: 本スレッドが稼働しているときの別スレッドでのボタン操作
□投稿者/ anny (3回)-(2011/01/03(Mon) 16:47:35)
2011/01/03(Mon) 17:26:58 編集(投稿者)
2011/01/03(Mon) 17:26:53 編集(投稿者)

Azulean様,回答ありがとうございます.

> ワーカースレッドでは受け取ったデータの解析、描画に必要なデータ生成までとし、実際の描画はメインスレッドに Invoke なり、BeginInvoke なりを使うか、Invalidate メソッドを呼ぶだけにして後でくる Paint イベントで描画するかでしょうか。
> ただ、スレッド間で同期をうまく取らないと、描画がずれる、データが上書きされるなどの問題が発生する可能性があります。

質問した箇所とは別の部分でInvokeを使って描画しているのですが,仰るとおりにスレッド間でうまく同期が取れなかったので結局(描画に必要なデータ生成+実際の描画)をInvokeで行っています.
描画部分のみをInvokeで行いたいのですが難しいです.

> 私がイベント駆動といったのは、「データを受け取った」と言ったようなイベントを受けて必要な処理をすることです。
> While ループで待つ代わりに、一度処理するごとにイベントハンドラから抜けて、次のイベントを待つ形です。

現状では自分でイベントを記述することができない状態なので,勉強してから今回のケースに対応できるかどうか試してみます.

今回はApplication.DoEventsを使って最初の質問部分に対応したいと思います.
問題が起きないことを祈りつつ…
ありがとうございました.
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -