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

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

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

Re[8]: 別スレッドのフォームをOwnerに指定したい


(過去ログ 65 を表示中)

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

■37758 / inTopicNo.1)  別スレッドのフォームをOwnerに指定したい
  
□投稿者/ IT (1回)-(2009/06/29(Mon) 21:07:44)

分類:[C#] 

あるフォームAの上に、別スレッドで作成したフォームBを重ねて表示したいと思っています。
(フォームBは、必ずフォームAよりも前に表示させたい)

スレッドを使用しないのであれば、「フォームB.Owner = フォームA」で良いと思うのですが、
別スレッドでこのような実装を行う場合はどうすれば良いのでしょうか。


※ちなみに、Invokeとdelegateを用いて「フォームB.Owner = フォームA」を実装してみたところ、一応、こちらの希望通りに表示してはくれたのですが、
フォームBを一度最大化してから元に戻そうとしたり、逆に最小化してタスクトレイに入れたものを元に戻そうとすると、
「コントロールが作成されたスレッド以外のスレッドからコントロール 'フォームA' がアクセスされました」と例外を発生してしまいました。
(どうやら、フォームBを元のサイズに戻そうとする際に、フォームBのOwner、すなわちフォームAへアクセスしているようです)

引用返信 編集キー/
■37761 / inTopicNo.2)  Re[1]: 別スレッドのフォームをOwnerに指定したい
□投稿者/ 囚人 (389回)-(2009/06/29(Mon) 21:46:16)
UI スレッドが2つ以上必要な状態は 99 % 設計ミスです。
これを避けるように設計できませんか?
どういう理由でそうしたいのでしょうか。

引用返信 編集キー/
■37801 / inTopicNo.3)  Re[2]: 別スレッドのフォームをOwnerに指定したい
□投稿者/ IT (2回)-(2009/06/30(Tue) 18:43:33)
No37761 (囚人 さん) に返信
> UI スレッドが2つ以上必要な状態は 99 % 設計ミスです。
> これを避けるように設計できませんか?
> どういう理由でそうしたいのでしょうか。

フォームAは、時間のかかる処理をおこなっていて、必要な場合に外部関数(コマンドライン)を呼び出します。

この外部関数の実行部分が、フォームAとは別スレッドになっているのですが、
外部関数と同時に作成したフォームBに、外部関数の進捗状況をプログレスバー等で表示しています。
(stdoutから取得しています)

このときのフォームBを、フォームAよりも必ず手前に表示させたいのです。

ちなみに、外部関数実行中(フォームB表示中)も、フォームAは最初の処理を引き続きおこなっています。
場合によっては複数のフォームBが起動することもあります。

引用返信 編集キー/
■37806 / inTopicNo.4)  Re[3]: 別スレッドのフォームをOwnerに指定したい
□投稿者/ まどか (613回)-(2009/06/30(Tue) 22:53:38)
No37801 (IT さん) に返信
> この外部関数の実行部分が、フォームAとは別スレッドになっているのですが、
> 外部関数と同時に作成したフォームBに、外部関数の進捗状況をプログレスバー等で表示しています。
>
> このときのフォームBを、フォームAよりも必ず手前に表示させたいのです。

普通にBを表示してBが外部関数やBackgroundWorkerからイベントを受け取るとか。
引用返信 編集キー/
■37807 / inTopicNo.5)  Re[3]: 別スレッドのフォームをOwnerに指定したい
□投稿者/ 倉田 有大 (670回)-(2009/06/30(Tue) 22:55:40)
フォームだけは同じスレッドで作るようにできないのでしょうか。
スレッドからイベントかなんかで、進捗を対応しているフォームに伝え、Invokeで画面を更新してやるとか。
引用返信 編集キー/
■37809 / inTopicNo.6)  Re[4]: 別スレッドのフォームをOwnerに指定したい
□投稿者/ 囚人 (390回)-(2009/07/01(Wed) 00:39:45)
>外部関数と同時に作成したフォームBに、外部関数の進捗状況をプログレスバー等で表示しています。

↑のフォームAとフォームBは同じスレッドに作成すべきです。

>ちなみに、外部関数実行中(フォームB表示中)も、フォームAは最初の処理を引き続きおこなっています。

↑だとしてもです。

同じスレッドの場合、フォームAが処理中だと、フォームBのプログレスバーが動かないと判断しているのかもしれませんが、そうはなりません。
仮に、フォームAが処理中に、フォームBが動かないような状態になったら、フォームAも描画がされなくなったりボタンが動かなかったりします。

画面がそれぞれ別スレッドで動く必要はまずありません。


引用返信 編集キー/
■37841 / inTopicNo.7)  Re[5]: 別スレッドのフォームをOwnerに指定したい
□投稿者/ IT (3回)-(2009/07/01(Wed) 18:32:31)
なるほど…やはりフォームAとフォームBは同一スレッドで起動すべきなんですね…

ちなみに、現在の状態を、究極までシンプルにしたソースは以下のとおりです。

----------
using System;
using System.Windows.Forms;
using System.Threading;

namespace FormTest
{
	// FormA
	public partial class FormA : Form
	{
		public FormA()
		{
			InitializeComponent();
		}

		private void button1_Click(object sender, EventArgs e)
		{
			// 時間のかかるメイン処理を別スレッドで起動
			Thread threadA = new Thread(new ThreadStart(MainFunc));
			threadA.Start();
		}

		delegate void label_Set_Delegate(string msg);
		private void label1_Set_Delegate(string msg)
		{
			label1.Text = msg;
			label1.Update();
		}

		private void MainFunc()
		{
			for (int i = 0; i <= 9; i++)
			{
				// 処理中のプロセス番号を表示
				Invoke(new label_Set_Delegate(label1_Set_Delegate), new object[] { i.ToString() });
				// ある条件でFormBを起動
				if ((i & 1) == 0)	// 仮に偶数のとき
				{
					FormB subForm = new FormB(i);
					subForm.ShowDialog();
				}
			}
		}

	}

	// FormB
	public partial class FormB : Form
	{
		private int proc;
		public FormB(int i)
		{
			InitializeComponent();

			proc = i;
		}

		private void Form2_Shown(object sender, EventArgs e)
		{
			this.Text = proc.ToString();	// フォームのタイトルにプロセス番号を表示
			progressBar1.Minimum = 0;
			progressBar1.Maximum = 9;
			Update();

			for (int i = 0; i <= 9; i++)
			{
				// 処理状況をプログレスバーで表示
				progressBar1.Value = i;
				Thread.Sleep(200);
			}

			// 終了したらフォームを閉じる
			this.Close();
		}
	}
}
----------

フォームAで行いたい処理(MainFunc)自体が、フォームAとは別スレッドになっていて、そのMainFuncからフォームBを起動しています。
「フォームAとフォームBを同一スレッドにする」ということは、MainFuncからのフォーム作成はNGということでしょうか?

フォームBが起動するのは「MainFuncが必要としたタイミング」なので、
どうしてもMainFuncから起動すること(すなわちフォームAとは別スレッド)になってしまうのですが…。


また、イベントを使う件ですが、外部関数の進捗状況は、stdoutに出力されたテキストを
フォームBが都合のよいタイミングで取得しているだけなので、イベント受け渡しにするのは難しいかと思っています。

引用返信 編集キー/
■37844 / inTopicNo.8)  Re[6]: 別スレッドのフォームをOwnerに指定したい
□投稿者/ Hongliang (431回)-(2009/07/01(Wed) 19:16:22)
> フォームBが起動するのは「MainFuncが必要としたタイミング」なので、
> どうしてもMainFuncから起動すること(すなわちフォームAとは別スレッド)になってしまうのですが…。
FormB の生成と表示を Invoke 経由にすればいい話ですね。

> また、イベントを使う件ですが、外部関数の進捗状況は、stdoutに出力されたテキストを
> フォームBが都合のよいタイミングで取得しているだけなので、イベント受け渡しにするのは難しいかと思っています。
タイマでも何でもやりようはあります。
引用返信 編集キー/
■37871 / inTopicNo.9)  Re[7]: 別スレッドのフォームをOwnerに指定したい
□投稿者/ IT (4回)-(2009/07/02(Thu) 11:50:44)
No37844 (Hongliang さん) に返信
>>フォームBが起動するのは「MainFuncが必要としたタイミング」なので、
>>どうしてもMainFuncから起動すること(すなわちフォームAとは別スレッド)になってしまうのですが…。
> FormB の生成と表示を Invoke 経由にすればいい話ですね。

言われてみればその通りでした。。。
FormBとFormBで行っている処理を切り離して、別スレッドにすれば解決ですね。

メインスレッド:FormA
 →スレッド1:MainFunc
  →スレッド2:FormBと、FormBの処理

となっているのを、

メインスレッド:FormA
 →スレッド1:MainFunc
  →メインスレッド:FormB(Invoke経由)
   →スレッド2:FormBの処理

にすれば良いと。

ありがとうございました。やってみます。
引用返信 編集キー/
■37901 / inTopicNo.10)  Re[8]: 別スレッドのフォームをOwnerに指定したい
□投稿者/ IT (5回)-(2009/07/02(Thu) 15:45:09)
フォームBをInvokeでメインスレッドに、今までフォームBで行っていた内部処理を別スレッドにすることで、無事にOwner設定もできました。

何も考えずにUIをスレッド化していたことを反省しました。

皆さんありがとうございました。

解決済み
引用返信 編集キー/


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

このトピックに書きこむ

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

管理者用

- Child Tree -