Form1からForm2をshowdialogで開いたときと同じ状態にしたいのですが、
そのまま showdialogでForm2を開いたら、Form1の処理が止まってしまいます。
Form1の処理を止めないで、showdialogと同じ状態でForm2を表示させるにはどうすればいいでしょうか?
…?やりたい事は十分つかめてませんが…
Form2.Show()
でどうにかしてみるとか?
System.Threading.Thread でマルチスレッド操作してみるとか?
Form1内でSystem.Threading.Threadを使う方法は知っているのですが、
Form1で処理を行いながら、
Form2でSystem.Threading.Threadを使い、Form1での値を受け取り、
その値を使って、ProgressBarを動かすにはどうしたらよいでしょうか?
>Form1で処理を行いながら、
>Form2でSystem.Threading.Threadを使い、Form1での値を受け取り、
>その値を使って、ProgressBarを動かすにはどうしたらよいでしょうか?
それを考え出すのがマグさんのお仕事です。全く想像できないようなものは
プログラムは作成できません。しかし、動作を説明できているのですから、
処理を分解して考え、順を追って工夫していけばできるんじゃないですか?。
今回の場合、まず
1、Form1 で処理を行いながら、System.Threading.Thread を使い Form2 を表示する。
2、System.Threading.Thread で実行中の Form2 に Form1での値を渡す。
3、その値を使って、ProgressBarを動かす。
といった所でしょうか?。
>Form1内でSystem.Threading.Threadを使う方法は知っているのですが、
Form2 を New するのは Form1 ででしょうし、Form2 は参照変数として
処理するんでしょ?だったら普通の変数と扱いは変わらないんじゃないですか?
マグさんの知ってる方法で十分にできそうな気がしますが??
> そのまま showdialogでForm2を開いたら、Form1の処理が止まってしまいます。
子画面をモーダルではなく、モードレスにて表示する方向で考えてみては?
または、Form1が処理して、Form1自身に表示させるというスタイルを変更して、処理をForm2(または別のクラス)が行うようにして、それをForm1に表示させるとか。
マグさんが各フォームで行っている処理がわからないので、回答しずらいのですが
.NET で、非同期プログラムを行うとなれば、こんなパターンがあります。
(1) BeginInvoke/EndInvokeを使う。
(2) IAsyncResult.IsCompletedをポーリングして完了チェック。
(3) BeginInvoke/WaitHandle/EndInvokeを使ってIAsyncResultを待機。
(4) デリゲートを渡して、コールバックしてもらう。
> 2、System.Threading.Thread で実行中の Form2 に Form1での値を渡す。
あれ。それってOKなんでしたっけ?
.NETの Windows フォームやコントロールは「スレッドセーフ」では無いので、独自作成のスレッドの中から、Windows.Forms のコントロールにアクセスするわけにはいかない、と理解していたのですが。
>> 2、System.Threading.Thread で実行中の Form2 に Form1での値を渡す。
>あれ。それってOKなんでしたっけ?
>.NETの Windows フォームやコントロールは「スレッドセーフ」では無いので、独自作成のスレッドの中から、
>Windows.Forms のコントロールにアクセスするわけにはいかない、と理解していたのですが。
それは多分…正しいと思います。
[マルチスレッド : 同期クラスの使用法]
http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/vccore/html/_core_multithreading.3a_.how_to_use_the_synchronization_classes.asp
[スレッド処理のデザイン ガイドライン]
http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/cpgenref/html/cpconthreadingdesignguidelines.asp
>インスタンス状態はスレッド セーフである必要がありません。既定では、クラス ライブラリはスレッド セーフではないことが必要です。
などの記述もあります。
スレッドセーフが重要なことは理解しているつもりですが、マルチスレッドは嫌って
使ってこなかったので(苦笑)不十分な点は多々あると思われます。ご指摘ありがとう
ございます。表現としても誤解を生みそうな回答ですよね。…訂正しようと思いましたが
上手い表現が見つかりませんでしたのでフォローできる方がいらっしゃいましたら
お願いします。
ただ、参照変数から Form クラスの関数などを利用する事は可能と思われます。
1、グローバルな参照変数(Form1 で有効なローカル変数)に Form2 のインスタンスを生成します。
2、スレッドで行うのはグローバルな Form2 の参照変数にアクセスして関数の実行などのみとします。
3、当初の質問で ShowDialog の状態を利用したいような書込みでしたので、スレッドは1つのみ起動するように
[VB.NET]
Dim t As New Thread(AddressOf ThreadProc)
With t
If .IsAlive Then
.Abort()
End If
End With
の処理を ShowDialog が解除された時点で適用しスレッドを殺してます。
4、Shared 宣言や参照変数のインスタンスが生成されているかを判断して 使用する Form2 のインスタンスは1つとします。
というような処理でそれなりに動くのは確認してます。…まぁ、処理として不安の
残る出来上がりなのでソースは公開したくないですし、
>子画面をモーダルではなく、モードレスにて表示する方向で考えてみては?
ボクもそっちの方がいいとは思ってますが…。…挑戦的な意味もこめてマルチスレッドの方向で回答をしようかと。
ありがとうございました。
特攻隊長まるるうさんの言うとおり
スレッドで出来ました。
でも、多少、処理は遅くなります。
話題が脱線しかけていますが、一応補足を。
例えば、グローバル変数を作って、複数のスレッドから
その変数にアクセスするのは、基本的に NG です。
それこそ、
myVar = myVar + 1
という単純なコードでさえ、「同時に実行」された時に問題になります。
(1) Thread1 が、変数 myVar の値を読む。
(2) (OS が)Thread1 を中断し、Thread2 を実行させる。
(3) Thread2 が、先の myVar の値を読む。
(4) Thread2 は、その値に1を加算して、myVar に格納する。
(5) Thread2 が中断され、Thread1 が再開。
(6) Thread1 も、先ほど読み取った値に 1 を加算して格納。
# 何が問題になっているかわかりますか?
上記のパターンで、myVar の値が 10 だったとします。
この時、(1) の段階で Thread1 に取得された値も、「10」です。
その後、(3) の段階で Thread2 に取得された値も、「10」です。
そして、(4) にて Thread2 は、myVar を「11」に更新します。
最後に、(6) にて Thread1 も、myVar を「11」に更新します。
Thread1 と Thread2 が、それぞれ1回ずつ(計2回)処理したのに、
増加した値は +2 ではなく、+1 になってしまうわけです。
# マルチスレッドプログラムで厄介なのは、こうした同時実行に関する
# 問題が発覚し難い(再現性が低い)事にあります。
このような問題を回避するためには、
(方法0) マルチスレッド化を諦める。
(方法1) そもそもグローバル変数を使わない。
(方法2) グローバル変数を使うにしても、1変数につき1スレッドだけが
アクセスする事にしておく。
(方法3) 複数のスレッドからアクセスしたいなら、何らかの「同期化」の
手法を用いて、複数のスレッドからアクセスできないようにする。
などの回避策が必要です。
なるほど。
スレッドを中断してたんですね。
道理で動きがおかしかったハズですね。←動いて止まって動いて止まっての連続でカウンターが増えていきました。
では、どのように記述すればいいか分かりません。
教えてください。
お願いします。