tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトルモードレスの終了
記事No8660
投稿日: 2009/01/31(Sat) 23:17
投稿者金本
VB.NET 2003
Windows XP

ご存知の方お力をお貸しください。

Form1からForm2をモードレスで呼出して、処理後Form2をクローズする時に
このForm2がCloseしていないようなのです。

Form1からの呼出し
Dim frmForm As New Form2

frmForm.Show()
frmForm = Nothing
Me.Hide()

Form2の終了
Dim frmForm As New Form1
frmForm.Show()
frmForm = Nothing
Me.Close()
Me.Dispose() <= 念のため入れてみましたが効果なしです。

Form2の表示自体はクローズするのですが、メモリを解放していない
ようなのです。

[ツリー表示へ]
タイトルRe: モードレスの終了
記事No8662
投稿日: 2009/02/01(Sun) 14:16
投稿者Abyss
Modelessでフォームを呼び出す
メリットは別として、

(Form2の終了)
Dim frmForm As New Form1
frmForm.Show()

の部分で新規のForm1インスタンスを作る必要は
ないと思います。

Form1.Show()

で十分だと思います。

[ツリー表示へ]
タイトルRe^2: モードレスの終了
記事No8669
投稿日: 2009/02/02(Mon) 08:51
投稿者金本
> Form1.Show()
>
> で十分だと思います。

これだと「非共有メンバを参照するには、オブジェクト参照が必要です。」
というエラーになりました。

[ツリー表示へ]
タイトルRe^3: モードレスの終了
記事No8675
投稿日: 2009/02/02(Mon) 11:28
投稿者YuO
> > Form1.Show()
> > で十分だと思います。

これは,VB 2005で追加された,悪名高き「暗黙のインスタンス」機能です。
使用には細心の注意を払う必要があります。


> これだと「非共有メンバを参照するには、オブジェクト参照が必要です。」
> というエラーになりました。

VB 2005からの機能なので,VB.NET 2003では使えません。
なお,この方法でも一回目は元々あったForm1のインスタンスと暗黙のインスタンスの2つができてしまいます。

Form2のコンストラクタで元のForm1を渡しておくなどして,
Form2のインスタンスが元のForm1のインスタンスを知っておけばよいでしょう。

[ツリー表示へ]
タイトルRe^4: モードレスの終了
記事No8676
投稿日: 2009/02/02(Mon) 11:35
投稿者金本
> Form2のコンストラクタで元のForm1を渡しておくなどして,
> Form2のインスタンスが元のForm1のインスタンスを知っておけばよいでしょう。

すみません勉強不足で、おっしゃられている内容がよくわかりません。
もう少し詳しく教えていただけますでしょうか?。
コンストラクタ、インスタンスについて、よろしくお願いします。

[ツリー表示へ]
タイトルRe^5: モードレスの終了
記事No8682
投稿日: 2009/02/02(Mon) 13:49
投稿者YuO
> コンストラクタ、インスタンスについて、よろしくお願いします。

細かく説明すると,掲示板の分量ではなくなるので,詳しくはMSDNを参照してください。
ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.1041/vbcn7/html/vbconWorkingWithObjects.htm
とか
ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.1041/vbcn7/html/vbconProgrammingWithObjects.htm
とかは読んだ方が良いでしょう。
# ms-helpのURIはパッチ等の当て具合によって異なるので,適当なURIに読み替えてください。

ネット上だと
http://msdn.microsoft.com/ja-jp/library/cc437208(VS.71).aspx
でしょうか。
# 後者は英語版しかなかったので,とりあえず省略。

・コンストラクタ
簡単に言うとSub Newのことです。
インスタンスを初期化するためのメソッドです。

・インスタンス
操作対象となる実体です。
VB.NETでは,基本的にNew classnameで作り出します。

[ツリー表示へ]
タイトルRe: モードレスの終了
記事No8673
投稿日: 2009/02/02(Mon) 11:02
投稿者ダンボ
このコードでForm2はクローズしていますよね。

ただ、隠れているForm1と新しく作ったForm1の両方が
存在するためにメモリ量の変化が少ないのでは。

[ツリー表示へ]
タイトルRe^2: モードレスの終了
記事No8677
投稿日: 2009/02/02(Mon) 11:37
投稿者金本
> このコードでForm2はクローズしていますよね。
>
> ただ、隠れているForm1と新しく作ったForm1の両方が
> 存在するためにメモリ量の変化が少ないのでは。

Form2とばかり思っておりましたが、実際の元凶はForm1なのですね!。
まったく眼中にありませんでした。

[ツリー表示へ]
タイトルRe^3: モードレスの終了
記事No8678
投稿日: 2009/02/02(Mon) 12:39
投稿者ダンボ
Abyssさんが、ポロリと言ったように

>    Modelessでフォームを呼び出す
>    メリットは別として、

@ModalでForm2を使用する方が楽
AForm2のModeless使用が必須ならば、Form1はForm2を呼び出したらCloseして、Form2で
 また新しいForm1を作れば楽(アプリケーションの連鎖)
という2つの基本方針の変更もちょっと検討してみてはどうですか?

[ツリー表示へ]
タイトルRe^4: モードレスの終了
記事No8679
投稿日: 2009/02/02(Mon) 12:45
投稿者金本
> @ModalでForm2を使用する方が楽
> AForm2のModeless使用が必須ならば、Form1はForm2を呼び出したらCloseして、Form2で
>  また新しいForm1を作れば楽(アプリケーションの連鎖)
> という2つの基本方針の変更もちょっと検討してみてはどうですか?

実際には、Form4までの4階層ありまして、Form1、Form2はForm4にたどり着くまでの
メニューなのです。
Aは良さげな感じなので試してみます。
ありがとうございました。

[ツリー表示へ]
タイトルRe^5: モードレスの終了
記事No8680
投稿日: 2009/02/02(Mon) 13:17
投稿者金本
ありがとうございました、とは言ってみたものの、

        Dim frmFor1 As New Form2
        frmForm.Show()
        frmForm = Nothing
        Me.Close()

これでやってみましたら、Form2を開いたと同時に
Form1、Form2の両方閉じてしまいました。

frmForm = NothingとMe.Close()間にDoeventsを
入れてみましたが、変わりませんでした。

[ツリー表示へ]
タイトルRe^6: モードレスの終了
記事No8683
投稿日: 2009/02/02(Mon) 13:54
投稿者YuO
> これでやってみましたら、Form2を開いたと同時に
> Form1、Form2の両方閉じてしまいました。

Application.Runに渡したFormを閉じたら,アプリケーションが終了するのは仕様です。
http://msdn.microsoft.com/ja-jp/library/ms157902.aspx

複数のFormを扱う場合,ApplicationContextを作ってそれをRunに渡すようにするのがよいです。
http://msdn.microsoft.com/ja-jp/library/system.windows.forms.applicationcontext.aspx
http://msdn.microsoft.com/ja-jp/library/ms157901.aspx

[ツリー表示へ]
タイトルRe^7: モードレスの終了
記事No8684
投稿日: 2009/02/02(Mon) 15:55
投稿者金本
> 複数のFormを扱う場合,ApplicationContextを作ってそれをRunに渡すようにするのがよいです。
なにやら私のレベルでは収拾つかない状態になり、わけがわからなくなりました。
で、モーダルでうまくいきました。

タスクバーにForm1からForm4まで、ズラズラ並んでしまうことを除けばイメ−ジ通りの
動きです。

Abyssさん、YuOさん、ダンボさん、ありがとうございました。

一応解決という事にさせていただきます。
ApplicationContextについては、後々試してみます。

[ツリー表示へ]
タイトルRe^8: モードレスの終了
記事No8685
投稿日: 2009/02/02(Mon) 16:39
投稿者ダンボ
> タスクバーにForm1からForm4まで、ズラズラ並んでしまうことを除けばイメ−ジ通りの
> 動きです。

寝た子を起こすのも何なんですが。。
要は、生成したFormのインスタンス(実体)を見失わなければ問題ないので、

Class CommonTable
Public Shared Form1 as Form
Public Shared Form2 as Form
Public Shared Form3 as Form
Public Shared Form4 as Form
End Class

のような共通テーブルを持ち、生成した人がインスタンスを記録し、破棄した人が
記録から消せば良いでしょう。

Form1からの呼出し
CommonTable.Form1 = Me
Dim frmForm As New Form2
CommonTable.Form2 = frmForm
CommonTable.Form2.Show()
Me.Hide()

Form2の終了
CommonTable.Form1.Show()
CommonTable.Form2 = Nothing
Me.Close()

手打ちなので文法誤りはご容赦。

[ツリー表示へ]
タイトルRe^9: モードレスの終了
記事No8686
投稿日: 2009/02/02(Mon) 17:43
投稿者Abyss
YuOさんの
>  悪名高き「暗黙のインスタンス」機能です。

なるほど。。Designerコードを確認しないまま
レスを書いてしまいました。失礼。。。
今回の操作レベルであれば、イベントを掴んで
処理するのもありですね。

(Form1からの呼出し)
    Dim frmForm As New Form2
    AddHandler frmForm.FormClosing, AddressOf frmClosing
    Hide()
    frmForm.Show()
        :
        :
Private Sub frmClosing(byval o as object, byval e as Eventargs)
    Show()
end sub

(Form2の終了)
Me.Close()

[ツリー表示へ]
タイトルRe^10: モードレスの終了
記事No8689
投稿日: 2009/02/03(Tue) 09:20
投稿者ダンボ
>     AddHandler frmForm.FormClosing, AddressOf frmClosing

なるほど、これでForm2のクローズを捕まえて自分自身をShowするということですね。
メリットとしては
・Form2は何も考えなくて済む。
・モードレスとして呼び出しながらモーダルっぽい制御ができる。
参考になりました。

[ツリー表示へ]
タイトルRe^10: モードレスの終了
記事No8690
投稿日: 2009/02/03(Tue) 10:38
投稿者YuO
> (Form1からの呼出し)
>     Dim frmForm As New Form2
>     AddHandler frmForm.FormClosing, AddressOf frmClosing

これもだめだったり……。
http://msdn.microsoft.com/ja-jp/library/system.windows.forms.form.formclosing.aspx
>  バージョン情報
> .NET Framework
> サポート対象 : 3.5、3.0、2.0

.NET Framework 1.1ならば,代わりにClosingイベント (2.0以降は推奨されていません) を使います。
http://msdn.microsoft.com/ja-jp/library/system.windows.forms.form.closing.aspx

[ツリー表示へ]
タイトルRe^11: モードレスの終了
記事No8691
投稿日: 2009/02/03(Tue) 11:12
投稿者Abyss
> (Form1からの呼出し)
>     Dim frmForm As New Form2
>     AddHandler frmForm.FormClosing, AddressOf frmClosing

> サポート対象 : 3.5、3.0、2.0

なるほど。いろいろとバージョン制限があるんですね。
参考になりました。

⇒    AddHandler frmForm.Closing, AddressOf frmClosing

[ツリー表示へ]
タイトルRe^12: モードレスの終了
記事No8704
投稿日: 2009/02/04(Wed) 17:56
投稿者金本
モーダルでうまくいったと思っていたのですが、
Form4からForm3に戻る時などに、Form3が最小化したまま
戻ってこない現象が発生したので、ダンボさんがNo.8685で
示されていた方法で試したところうまくいきました。
それで、新たに質問が発生しまして「なおき」名義で
質問したところ、管理人さんに怒られまして再度、こちらに
質問させていただきます。
できたと言っておきながらすみませんが、教えてください。

Form4がテキストボックスが多すぎて、フォームを開くのに
時間がかかるため、Form1で
Dim frmForm As New Form4
CommonTable.Form4 = frmForm
と記入し、かなりスピードが改善されました(その分Form1は遅くなりましたが)。
ただ、Me.Hide()で閉じて、Form3から CommonTable.Form4.Show()
で開いた時に、画面初期化をしたいのですが、Form4.Activedで
初期化してしまうと、別のウィンドゥから戻ってきただけで
初期化処理が動いてしまう為、困っております。

Me.Hide()した状態から、.Show()されたときだけ、初期化処理を実行させる
方法はないでしょうか。
よろしくお願いします。

[ツリー表示へ]
タイトルRe^13: モードレスの終了
記事No8710
投稿日: 2009/02/05(Thu) 09:54
投稿者ダンボ
> Me.Hide()した状態から、.Show()されたときだけ、初期化処理を実行させる
> 方法はないでしょうか。

私の泥臭い(でもわかりやすい)方法で進んでいるわけですね。
Show対象のFormがわかっているのだから、例えばForm1のメンバー関数
Public ReActivated as Boolean
などを定義しておいて、Form2がForm1をShowするときに
CommonTable.Form1.ReActivated = True
などとすれば、.Hideからの.Showと単純Activateの区別ができますね。

ただ、他のフォーム内の変数を書き換えるのってちょっとやだ。
そこで折角CommonTableを導入したのなら、
Class CommonTable
Public Shared Form1 as Form
Public Shared Form1State as State
Public Shared Form2 as Form
Public Shared Form2State as State
Public Shared Form3 as Form
Public Shared Form3State as State
Public Shared Form4 as Form
Public Shared Form4State as State
End Class

Stateは列挙体で、HiddenとかActivatedとかClosedとかReActivatedとか定義するですね。

[ツリー表示へ]
タイトルRe^14: モードレスの終了
記事No8711
投稿日: 2009/02/06(Fri) 13:00
投稿者金本
ダンボさん、ご教授いただきありがとうございました。
また、連絡が遅くなりすみませんでした。
教えていただきました方法を試してみたところ
> Public Shared Form1State as State

as State を指定することができませんでした。
as StateChangeEventHandlerとか、as StateChangeEventArgs
などしか、指定できませんでした。

> Stateは列挙体で、HiddenとかActivatedとかClosedとかReActivatedとか定義するですね。

ReActivatedがありませんでした。

CompactFramework1の開発環境だからなのかはわかりませんが....。

[ツリー表示へ]
タイトルRe^15: モードレスの終了
記事No8712
投稿日: 2009/02/06(Fri) 15:13
投稿者ダンボ
> > Stateは列挙体で、HiddenとかActivatedとかClosedとかReActivatedとか定義するですね。
    Public Enum State
        Activated
        ReActivated
        Active
        Hidden
        Closed
    End Enum
Vb.netに備わっているものではないので、このように自分で定義する必要があります。

また上記に列挙しているものも必要十分な状態かどうかは疑問です。再考したほうが
よいです。状態遷移図を描いて、Stateに対して、誰が・いつ・何をセットするのか
書き出しておかないとバグの元です。

下記は一例です。
Form1をShowしようとする人は、Form1Stateを見て
・HiddenだったらForm1StateにReActivatedを入れてShow
・Closedだったら新しくForm1を作ってForm1StateにActivatedを入れてShow
・Activated/ReActivated/ActiveだったらForm1は動いているはずなので何もしない
Form1のActivateイベント処理では、Form1Stateを見て
・Activatedだったら初めての起動なので初期処理をしてStateをActiveに変える
・ReActivatedだったらHiddenからの復帰なので初期処理せずにStateをActiveに変える

[ツリー表示へ]
タイトルRe^16: モードレスの終了
記事No8713
投稿日: 2009/02/06(Fri) 17:03
投稿者金本
> > > Stateは列挙体で、HiddenとかActivatedとかClosedとかReActivatedとか定義するですね。
>     Public Enum State
>         Activated
>         ReActivated
>         Active
>         Hidden
>         Closed
>     End Enum
> Vb.netに備わっているものではないので、このように自分で定義する必要があります。

列挙体とは、そういう意味だったんですね。
わざわざ、ありがとうございました。
また経過を報告します。

[ツリー表示へ]
タイトルRe^17: モードレスの終了
記事No8714
投稿日: 2009/02/07(Sat) 02:39
投稿者金本
ダンボさん、できました。
ありがとうございました。

ただ、あまり本件と関係ないかもしれませんが

HideからShow()したときに
フォーカスが何処にもない状態になります。
Activatedで、TextBox1.Focus()を指定しても
一瞬TextBox1にフォーカスされた後、消えてどこにも
フォーカスされていない状態になります。

Private Sub Form2_Activated(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Activated

    if CommonTable.Form2State = Module1.State.ReActivated Then
        TextBox1.Focus()
    Else
        TextBox2.Focus()
    End If
    CommonTable.Form2State = Module.State.Active
End Sub

CloseからのShow()の場合は、TextBox2にフォーカスされるのですが
この違いがよくわかりません。

[ツリー表示へ]
タイトルRe^18: モードレスの終了
記事No8715
投稿日: 2009/02/07(Sat) 07:19
投稿者ダンボ
> HideからShow()したときに
> フォーカスが何処にもない状態になります。
> Activatedで、TextBox1.Focus()を指定しても
> 一瞬TextBox1にフォーカスされた後、消えてどこにも
> フォーカスされていない状態になります。

私には分かりません。
Activatedイベントが起きるのは、
新規起動のとき/Hiddenからの復帰/制御権再取得のとき
の3ポイントあると思いますがそれは考慮済み。

まじめに追求するとすれば、初期処理だのその他の処理を
消して、フォーカスだけに絞ったテストモジュールを作成して
原因を絞り込んで行くですかね。

[ツリー表示へ]
タイトルRe^19: モードレスの終了
記事No8716
投稿日: 2009/02/07(Sat) 08:46
投稿者金本
>> Activatedイベントが起きるのは、
> 新規起動のとき/Hiddenからの復帰/制御権再取得のとき
> の3ポイントあると思いますがそれは考慮済み。
>
> まじめに追求するとすれば、初期処理だのその他の処理を
> 消して、フォーカスだけに絞ったテストモジュールを作成して
> 原因を絞り込んで行くですかね。

はい、わかりました。
やってみます。
また経過を報告します。

[ツリー表示へ]
タイトルRe^20: モードレスの終了
記事No8717
投稿日: 2009/02/07(Sat) 09:47
投稿者金本
その後の経過です。

    Private Sub Form2_Activated(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Activated
        If commontable.form1state = Module1.State.reactivated Then
            TextBox2.Text = "abcd"
            TextBox2.Focus()
        Else
            TextBox2.Text = ""
            TextBox1.Focus()
        End If
        Application.DoEvents
        commontable.form1state = Module1.State.activated
    End Sub

という風に、TextBox2に文字"abcd"を入れる処理を追加してみましたら
それは動きます、が、フォーカスだけされませんでした。
不思議です、また経過を報告します。

[ツリー表示へ]