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

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

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

Re[17]: フォームのモーダル制御について


(過去ログ 70 を表示中)

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

■40380 / inTopicNo.1)  フォームのモーダル制御について
  
□投稿者/ らんぺるーる (86回)-(2009/08/24(Mon) 19:28:39)

分類:[VB.NET/VB2005 以降] 

以下手順@ABのようなフォームの呼び出し関係の場合のモーダル制御の方法について質問させてください。

@フォーム「test1」、フォーム「test2」、フォーム「test3」を作成する。
Aフォーム「test1」よりフォーム「test2」をShowする。
----フォーム「test1」のコード----
Dim instTest2 As New test2
test2.Show
→Showを使用しているので、フォーム「test1」、フォーム「test2」は両方とも操作できます。
Bフォーム「test1」よりフォーム「test3」をShowDialogする。
----フォーム「test1」のコード----
Dim instTest3 As New test3
test3.ShowDialog
→ShowDialogを使用しているので、フォーム「test1」は操作できず、フォーム「test3」は操作できます。

-問題点-
上記Bを実施後、フォーム「test2」についても、操作ができなくなってしまう。

-質問内容-
フォーム「test3」をShowDialogしたあとも、フォーム「test2」は操作ができるようにしたいのですが、
方法がわかりません。アドバイスをいただけないでしょうか。

・ShowDialogに関係なく、常に操作が可能なフォームを用意したいということです。

引用返信 編集キー/
■40382 / inTopicNo.2)  Re[1]: フォームのモーダル制御について
□投稿者/ やじゅ (1258回)-(2009/08/24(Mon) 19:57:00)
やじゅ さんの Web サイト
2009/08/24(Mon) 20:02:39 編集(投稿者)

No40380 (らんぺるーる さん) に返信
> ・ShowDialogに関係なく、常に操作が可能なフォームを用意したいということです。

最近、同じ内容の質問を受けたなー
http://bbs.wankuma.com/index.cgi?mode=al2&namber=40160

モーダレスだけどモーダルのように制御するようにしてますね。
1.Ownerプロパティに起動元(Me)をセット後にShowメソッド
2.起動元のActivatedイベントで、サブ画面をアクティブにする

モードレスのフォームが、あるフォームの背後に隠れないようにする
http://dobon.net/vb/dotnet/form/ownedform.html

引用返信 編集キー/
■40446 / inTopicNo.3)  Re[2]: フォームのモーダル制御について
□投稿者/ らんぺるーる (87回)-(2009/08/26(Wed) 11:18:15)
No40382 (やじゅ さん) に返信
> 2009/08/24(Mon) 20:02:39 編集(投稿者)
>
> ■No40380 (らんぺるーる さん) に返信
>>・ShowDialogに関係なく、常に操作が可能なフォームを用意したいということです。
>
> 最近、同じ内容の質問を受けたなー
> http://bbs.wankuma.com/index.cgi?mode=al2&namber=40160
>
> モーダレスだけどモーダルのように制御するようにしてますね。
> 1.Ownerプロパティに起動元(Me)をセット後にShowメソッド
> 2.起動元のActivatedイベントで、サブ画面をアクティブにする
>
> モードレスのフォームが、あるフォームの背後に隠れないようにする
> http://dobon.net/vb/dotnet/form/ownedform.html
>


すみません、全く同じ質問がありました。
「2.起動元のActivatedイベントで、サブ画面をアクティブにする」
の内容がちょっとわからなかったです。
サブ画面は何もしなくてもShowしただけでアクティブになっていませんか?
(私の例ではサブ画面がフォーム「test3」、起動元がフォーム「test1」だと
解釈いたしました。)

逆に、何もしないとサブ画面「test3」を起動した後も
起動元のフォーム「test1」がアクティブになってしまうので、
「test3」を呼び出した後に、自分のフォームを非アクティブにする必要
があるのではないかと思います。

----フォーム「test1」のコード----
Dim instTest3 As New test3
test3.Show(Me)
Me.Enable = False←これを追加する

また、呼び出し先のフォーム「test3」の
FormClosedイベントで呼び出し元のフォームを
アクティブにする必要があるのではないかと思います。

----フォーム「test3」のFormClosedイベント----
Me.Owner.Enabled = True

私のコード、考え方に問題等ないでしょうか?
(ShowDialogを使用した場合と動作が異なってしまう箇所は把握しておきたいです。)
もっと影響が少ない修正方法があれば教えていただけないでしょうか。
引用返信 編集キー/
■40449 / inTopicNo.4)  Re[3]: フォームのモーダル制御について
□投稿者/ らんぺるーる (88回)-(2009/08/26(Wed) 11:32:15)
影響が少ない修正方法についてですが、
フォーム「test2」のみ別のアプリケーションで作成して、
呼び出せば、ShowDialogの影響をうけずに済むのではないか
と思いました。
(私のケースのように、「test2」とアプリケーション間で
処理の連携が少ない場合に限るとは思いますが)
引用返信 編集キー/
■40477 / inTopicNo.5)  Re[4]: フォームのモーダル制御について
□投稿者/ らんぺるーる (89回)-(2009/08/26(Wed) 19:04:30)
簡単にできる2つめの案として、フォーム「test2」のみ
別スレッドで表示(Show)しようとしましたが、Windowsフォームは
マルチスレッドでは対応していないようでした。
「現在のスレッドはシングル スレッド アパートメントでないため、
ActiveX コントロールをインスタンス化できません。」が発生しました。

なにかスレッド関係で簡単な解決方法はないでしょうか。
引用返信 編集キー/
■40481 / inTopicNo.6)  Re[3]: フォームのモーダル制御について
□投稿者/ まどか (621回)-(2009/08/26(Wed) 20:17:50)
No40446 (らんぺるーる さん) に返信
> 逆に、何もしないとサブ画面「test3」を起動した後も
> 起動元のフォーム「test1」がアクティブになってしまうので、
> 「test3」を呼び出した後に、自分のフォームを非アクティブにする必要
> があるのではないかと思います。

ですね。
その方法の一つをやじゅさんが書かれています。


> ----フォーム「test1」のコード----
> Dim instTest3 As New test3
> test3.Show(Me)
> Me.Enable = False←これを追加する
>
> また、呼び出し先のフォーム「test3」の
> FormClosedイベントで呼び出し元のフォームを
> アクティブにする必要があるのではないかと思います。
>
> ----フォーム「test3」のFormClosedイベント----
> Me.Owner.Enabled = True

アクティブとはいわゆるタイトルバーが濃い青い状態でキー入力を受け付ける状態といっていいでしょう。
対してEnabledは操作を不可とする、つまりイベントが起きない状態といっていいでしょう。
ポイントは前者で、フォーム1がクリックなどでアクティブになってもフォーム3をすぐにアクティブにする
という方法の一つを書かれているのがやじゅさんです。

> なにかスレッド関係で簡単な解決方法はないでしょうか。

スレッドは並行処理なのでモーダルの動作やアクティブであることとは無関係です。

ShowDialogが「アプリケーションモーダル」の動作である以上、やじゅさんが書かれたような方法に行きつくと思います。
#モーダルを使わずモーダルのような動作を実現する標準の方法が無いということです。

逆にフォームの説明を技術的なものではなく、具体的な仕様(業務操作)で説明していただけると
業務仕様に沿った代替案回答が得られるのではと思います。
引用返信 編集キー/
■40484 / inTopicNo.7)  Re[4]: フォームのモーダル制御について
□投稿者/ なちゃ (321回)-(2009/08/26(Wed) 20:53:38)
スレッド作成した時にThread.SetApartmentState使ってSTAに設定し、
ついでにいくつかの手順を使えば複数スレッドでそれなりにうまく動作させることはできますが、
いろんな意味でリスクがあるのであまりおすすめできません。
有名サードパーティのコントロールなんかではうまく動作しないものがあります。

引用返信 編集キー/
■40485 / inTopicNo.8)  Re[4]: フォームのモーダル制御について
□投稿者/ らんぺるーる (90回)-(2009/08/26(Wed) 21:00:29)
No40481 (まどか さん) に返信
> アクティブとはいわゆるタイトルバーが濃い青い状態でキー入力を受け付ける状態といっていいでしょう。
> 対してEnabledは操作を不可とする、つまりイベントが起きない状態といっていいでしょう。
> ポイントは前者で、フォーム1がクリックなどでアクティブになってもフォーム3をすぐにアクティブにする
> という方法の一つを書かれているのがやじゅさんです。

→「2.起動元のActivatedイベントで、サブ画面をアクティブにする」の意図が理解できました。 
 解説ありがとうございます。私、理解力がないですね…。
 上記方法についてですが、何らかの(予期しない)操作で起動元のコントロールが触られることがないかが心配です。
 大丈夫ですかね?。
 問題がなければ、起動元のみの影響で修正できるので、影響範囲が少なく、魅力的です。

 フォーム「test2」の仕様は、以下のようなものです。
 @フォーム「test2」はいろいろな画面から呼ばれるフォーム。(chmヘルプのようなイメージです。)
 A他の画面からフォーム「test2」を開く場合は、引数で呼び元の画面に対応したHTMLファイルのパスを受け取り、
  フォーム「test2」画面に配置したWebBrowserコントロールにHTMLファイルを表示する。
  (HTMLファイルには、呼び元の画面説明が記載されています。)
 Bフォーム「test2」が既に開かれた状態で、別の画面から開こうとした場合は、
  2つ以上フォーム「test2」は作成せず、呼び出し元の画面に対応したHTMLの切り替えのみを行う。

 上記仕様のため、常にフォーム「test2」は操作ができるようにしたいのです。
 いろいろな画面の中には、「test1」「test3」のような関係の画面があります。

  →以下サンプルコードで示すとおり、フォーム「test2」を開く処理は、共通化がされているため、
   フォーム「test2」を別アプリケーションで作成した場合は、影響を最小限に留められます。
   (共通関数のみ直せばいいため)
   ところが、Bの処理で現在詰まっております。

共通化は以下のイメージです。
---------------フォーム「test1」---------------
[test2の表示ボタンを押した場合の処理]
OpenForm2("test1.html")
[test3の表示ボタンを押した場合の処理]
Dim instTest3 As New test3
test3.ShowDialog

---------------フォーム「test3」---------------
[test2の表示ボタンを押した場合の処理]
OpenForm2("test3.html")

---------------共通関数---------------
[test2の表示処理(共通化)]
Public instTest2 As test2
Public Sub OpenForm2(ByVal PrmHtml As String)
    If instTest2 Is Nothing Then
        instTest2 = New test2
        test2.SetHtml(PrmHtml)
        test2.Show
    Else
        test2.SetHtml(PrmHtml)
    End If 
End Sub

---------------フォーム「test2」---------------
Private ShowHtml As String
[HTMLの表示/切り替え処理]
Public Sub SetHtml(ByVal PrmHtml As String)
    'ここに受け取ったHTMLファイルをWebBrowserコントロールに 
   表示する処理を書いています。
End Sub

 *出来る限り、複数のクラスに手をいれず、対応ができればと考えています。(開発規模の問題より)
 (呼び出し元全てのクラスに手を入れるのは避けたいです。)

引用返信 編集キー/
■40487 / inTopicNo.9)  Re[5]: フォームのモーダル制御について
□投稿者/ まどか (624回)-(2009/08/26(Wed) 21:14:05)
No40485 (らんぺるーる さん) に返信

仕様を見る限り、test2は別プロセス(アプリケーション)にしたほうがよいという印象があります。
#本体への依存性も薄いようですし。

実現方法としては、

1.プロセス間通信をおこなう。
または
2.test2のEXEプロジェクトを本体のプロジェクトで参照設定する。
  → test2側の本体からアクセスされるクラスのメンバをSharedにする。(本体のどのフォームもインスタンスを意識せず呼ぶだけ)

といったところでしょうか。

引用返信 編集キー/
■40488 / inTopicNo.10)  Re[5]: フォームのモーダル制御について
□投稿者/ らんぺるーる (91回)-(2009/08/26(Wed) 21:19:50)
No40484 (なちゃ さん) に返信
> スレッド作成した時にThread.SetApartmentState使ってSTAに設定し、
> ついでにいくつかの手順を使えば複数スレッドでそれなりにうまく動作させることはできますが、
> いろんな意味でリスクがあるのであまりおすすめできません。
> 有名サードパーティのコントロールなんかではうまく動作しないものがあります。
>

→了解です。マルチスレッドについては、コーディングも複雑になりますし、
 動作のリスクも高そうなので、見送ろうかと考えております。

 あとは、なちゃさんが最初に提示してくれた、Showを使用した方法にするか、
 「test2」のフォームを用意した別アプリケーション
 (以下「test2アプリケーション」と略します)として起動する方法のどちらかに絞られそうです。

 「test2アプリケーション」にした場合の問題は、上の投稿で書いたBの仕様をどのように実現するかです。

 「test2アプリケーション」を2個開かずに(既に開かれているか調べるのは簡単にできると思います。)
 WebBrowserコントロールのHTMLページを呼び出し元の画面に切り替える処理についてですが、

 既に開かれている「test2アプリケーション」に対して、別のプログラムから「test2アプリケーション」に
 用意したメソッド(HTML切り替えメソッドのようなもの)を発行することはできるのでしょうか?

 初めてオープンされる際は、「test2アプリケーション」の起動パラメータにHTMLファイルパスを用意すれば対応が可能です。
 既にオープンされている場合に、どのようにHTMLページを切り替えるかが問題です。


 



引用返信 編集キー/
■40489 / inTopicNo.11)  Re[6]: フォームのモーダル制御について
□投稿者/ まどか (625回)-(2009/08/26(Wed) 21:29:37)
No40488 (らんぺるーる さん) に返信
>  「test2アプリケーション」にした場合の問題は、上の投稿で書いたBの仕様をどのように実現するかです。

別アプリ
Public Class Test2
    Private Shared _MainForm As test2
    Public Shared Sub ShowHtml()
        If _MainForm Is Nothing Then
            _MainForm = New test2
        End If
        _MainForm.Show()
    End Sub
End Class

本体
Private Sub Test()
    Test2App.Test2.ShowHtml() どこからも同じ形です。
End Sub

という感じです。

引用返信 編集キー/
■40490 / inTopicNo.12)  Re[6]: フォームのモーダル制御について
□投稿者/ らんぺるーる (92回)-(2009/08/26(Wed) 21:29:39)
No40487 (まどか さん) に返信
> ■No40485 (らんぺるーる さん) に返信
>
> 仕様を見る限り、test2は別プロセス(アプリケーション)にしたほうがよいという印象があります。
> #本体への依存性も薄いようですし。
>
> 実現方法としては、
>
> 1.プロセス間通信をおこなう。
> または
> 2.test2のEXEプロジェクトを本体のプロジェクトで参照設定する。
>   → test2側の本体からアクセスされるクラスのメンバをSharedにする。(本体のどのフォームもインスタンスを意識せず呼ぶだけ)
>
> といったところでしょうか。
>
回答有難うございます、案2が非常に簡易で影響範囲が少なく対応できそうですので、試してみます。
また、分からないことがあったら質問させてください。
引用返信 編集キー/
■40491 / inTopicNo.13)  Re[7]: フォームのモーダル制御について
□投稿者/ まどか (626回)-(2009/08/26(Wed) 21:31:15)
訂正

> 別アプリ
> Public Class Test2Class  ※名前が重なってました。。。
> Private Shared _MainForm As test2

引用返信 編集キー/
■40496 / inTopicNo.14)  Re[8]: フォームのモーダル制御について
□投稿者/ らんぺるーる (94回)-(2009/08/26(Wed) 22:12:03)
No40491 (まどか さん) に返信
> 訂正
>
>>別アプリ
>>Public Class Test2Class  ※名前が重なってました。。。
>> Private Shared _MainForm As test2
>

別アプリ試しました!
同じアプリケーション内と動作が同じだったのですが、
私の実装が悪いのでしょうか?

test2は新アプリケーションで作成しましたが、
呼び出し元がメインアプリケーションなので、
モーダルの影響を受けてしまうのでしょうか…。
引用返信 編集キー/
■40497 / inTopicNo.15)  Re[9]: フォームのモーダル制御について
□投稿者/ らんぺるーる (96回)-(2009/08/26(Wed) 22:29:41)
実装の方法を書きます。

@メインプロジェクトから「ファイル→追加→既存項目の追加」でTest2プロジェクトを追加。

以下作成したコードイメージです。
[メインプロジェクト側]
---------------フォーム「test1」---------------
[test2の表示ボタンを押した場合の処理]
OpenForm2("test1.html")
[test3の表示ボタンを押した場合の処理]
Dim instTest3 As New test3
test3.ShowDialog

---------------フォーム「test3」---------------
[test2の表示ボタンを押した場合の処理]
OpenForm2("test3.html")

---------------共通関数(モジュール)---------------
[test2の表示処理(共通化)]
Public instTest2 As test2
Public Sub OpenForm2(ByVal PrmHtml As String)
test2App.CommonTest2.ShowHelp(PrmHtml)
End Sub


[test2Appプロジェクト側]
---------------共通関数(「CommonTest2」モジュール)---------------
Public instTest2 As test2
Public Sub ShowHelp(ByVal PrmHtml As String)
If instTest2 Is Nothing Then
instTest2 = New test2
test2.SetHtml(PrmHtml)
test2.Show
Else
test2.SetHtml(PrmHtml)
End If

---------------フォーム「test2」---------------
Private ShowHtml As String
[HTMLの表示/切り替え処理]
Public Sub SetHtml(ByVal PrmHtml As String)
'ここに受け取ったHTMLファイルをWebBrowserコントロールに 
   表示する処理を書いています。
End Sub

*これでは、同じプロセスになる気がします。
引用返信 編集キー/
■40498 / inTopicNo.16)  Re[10]: フォームのモーダル制御について
□投稿者/ らんぺるーる (97回)-(2009/08/26(Wed) 22:31:34)
すみません。手順について
Aプロジェクト→参照の追加→プロジェクト→「test2App」
が漏れました。
引用返信 編集キー/
■40501 / inTopicNo.17)  Re[11]: フォームのモーダル制御について
□投稿者/ らんぺるーる (98回)-(2009/08/26(Wed) 22:43:20)
うーん、ちょっと調べてみましたが、この方法で実装をすると、
「複数のプロジェクトを含むソリューション」というだけで、
別アプリケーションというわけではないのではないでしょうか。
引用返信 編集キー/
■40503 / inTopicNo.18)  Re[12]: フォームのモーダル制御について
□投稿者/ まどか (627回)-(2009/08/26(Wed) 23:13:43)
No40501 (らんぺるーる さん) に返信
> 別アプリケーションというわけではないのではないでしょうか。


すいません。
そのとおりですね。。。

1.WCFをつかう。※Framework3.0
2.APIでプロセス間通信をおこなう。※パイプとか
http://msdn.microsoft.com/ja-jp/library/cc392662.aspx
3.Sub Main+二重起動禁止チェックにして、引数の情報からフォームの更新をおこなう。(未検証)

というところでしょうか。

引用返信 編集キー/
■40506 / inTopicNo.19)  Re[13]: フォームのモーダル制御について
□投稿者/ やじゅ (1270回)-(2009/08/27(Thu) 00:12:29)
やじゅ さんの Web サイト
2009/08/27(Thu) 00:13:48 編集(投稿者)

> ■No40501 (らんぺるーる さん) に返信

test2Appは、Process.Startを使って表示させる。二重起動禁止チェックはしないと2つ開いてしまうから注意
HTMLファイルパスくらいの文字列なら、WM_COPYDATAを使ってtest2Appに渡せばいいかも。
WndProcでWM_COPYDATAで文字列を受信したら、WebBrowserコントロールに文字列を渡す。

引用返信 編集キー/
■40521 / inTopicNo.20)  Re[13]: フォームのモーダル制御について
 
□投稿者/ らんぺるーる (99回)-(2009/08/27(Thu) 12:00:53)
1.WCFをつかう。※Framework3.0
→現在のユーザの環境はFramework2.0までを用意としておりますので、
この方法は今回は見送ろうと思います。

2.APIでプロセス間通信をおこなう。※パイプとか
http://msdn.microsoft.com/ja-jp/library/cc392662.aspx
→やじゅさんの方法とあわせて、検証しようと思います。
プロセス間通信は今までやったことがないので、また質問させていただくかもしれませんが、
その際は宜しくお願いいたします。

3.Sub Main+二重起動禁止チェックにして、引数の情報からフォームの更新をおこなう。(未検証)
→この方法については、既に検証をしましたが、初回起動時は起動パラメータ渡しでOKですが、
 2回目以降の情報の渡し方で詰まってしまいました。
 アドバイスがあればお願いいたします。




引用返信 編集キー/

次の20件>
トピック内ページ移動 / << 0 | 1 >>

管理者用

- Child Tree -