こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

指定の動作中ユーザーフォーム終了方法

お世話になっております。
タイトルに書ききれなかったため、詳しく書かせていただきます。

UserForm
UserFormA
UserFormB
UserFormC があります。

UserFormには、UserFormA,UserFormB,UserFormCを起動するための
コマンドボタンが配置されています。

UserFormA.Show とかです。

UserFormAは、UserFormB,UserFormCと連携して
グラフを作成したりします。

UserFormAのCombobox1には、値が入っており、
UserFormAのCommandButtonを押したら、
UserFormAのCombobox1の値をUserFormBに入れてCommandbuttonを押す、
UserFormAのCombobox1の値を,UserFormC入れてCommandbuttonを押す
という動作をしております。

今まで、UserFormを閉じる動作をしたら
「閉じますか?」という確認ウィンドウが出て、
強制的にEndで終わりにしておりました。

------------------------------------
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)

If CloseMode = vbFormControlMenu Then '終了するって書いたら
Cancel = Not FP_GetResult

If Cancel = 0 Then 'はい を押した場合の判断
With ThisWorkbook.Worksheets("TEST")
.Select
End With
End
End If
End If
'「はい」を押さない場合、終了しない。
Application.ScreenUpdating = True
End Sub

' キャンセルするかを確認する処理
Private Function FP_GetResult() As Integer
If MsgBox("終了しますか?", vbInformation + vbYesNo) = vbYes Then
FP_GetResult = True
Else
FP_GetResult = False
End If
End Function
----------------------------------

ただ、今回は大元のUserFormも起動しており、
UserFormは終了させたくありません。(再表示ということでも良いのですが…)

If UserForm.Visible = False Then
UserForm.Show
End If

上記で、UserFormが表示されているか確認はできますが、
Endの前に入れようと、後に入れようと
UserForm.showが実行されることはありません。
だからといって、Exit Subを使うと
UserFormB,UserFormCの動作を継続して行ってしまいます。

分かりにくいところがあれば追記しますので、
回答をお願い致します!

投稿日時 - 2014-07-09 17:42:51

QNo.8671316

困ってます

質問者が選んだベストアンサー

#3で、ああ書いておけば具体的なソースコードやプロットが返ってくるかと期待していましたが、
どうも今回はコミュニケーション・エラーばかり目立っていて、うまくいきませんね。
出口が見つからなくなってしまいました。
限られた情報の中で私の推理力を試されているようにも感じていますけれど、
今一度だけお応えします。更に続けてレスを重ねることはしませんので悪しからず。

ところで、
> End を記入し、強制終了させるしかなさそうな
どうしてもそういう結論に導きたいのでしたら、ご自由にどうぞ。
そもそも今時、何故End ステートメントに拘るのか解りませんが、
生憎、End ステートメントを使って解決に導くようなレスは私には書けませんので、
そういう意味で期待外れでしたらば、以下読まずに無視してください。
でも、End ステートメントを使うデメリットについても知っておいてください。
例えば、VBAProjectが終了(リセット)されるまで値を保持してくれるスタティックな変数
(Static、Private、Public、Friendなどのキーワードで定義する変数のこと)、
これを使えないのは、設計やコーディングの手法を大きく限定してしまうことになります。
他の部分で何を書くのにも手間を増やさなければなりませんから、
一般論として、その場凌ぎにはなっても、"自分さえ良ければいい"的な、負の遺産でしかありません。
また、これらスタティックな変数を使わないでも成立するプロジェクトって、
そう多くはないのではないでしょうか。
もっとも、ひとつのプロジェクトにひとつのマクロというような扱いで、
且つ外部のオブジェクトを一切扱わないならば、
(それとも全知全能なVBAプログラマーが正しい使い方をするのならば)
"どうぞお使いください"ってことではあります。
あと、正しくプロシージャを抜ければ、正しく解放されるオブジェクト等でも
End ステートメントのおかげでTempフォルダに残骸を残し、
ゆくゆくはExcelアプリケーションの挙動にまで悪影響を及ぼような事例もあったと思います。
まぁ一時的に変更しておいたプロパティ(例:Application.Calculation = False)等を
End ステートメントだけの為に態々元に戻すのも面倒ですよね。
実の所、ひとつひとつの記述を正しく書き直すことができれば、
End ステートメントは使う必要がない、と断言してもいいのかなって思いますけれど。
逆にEnd ステートメントでなきゃうまく行かない、と感じてしまうということは、
間違いに目が行ってない気が付いていない、って時なんじゃないでしょうかね?
私の経験として、「非同期の外部オブジェクトを複数ループさせて、
リターンが返ったタイミングのイベントを使っていた時」、
「中止ボタンですべて中止するように書いていたつもりが
外部オブジェクトのイベントを止められていなかった」ことに気が付いた時、
私も一瞬「End ステートメントを使えれば楽なのに」と思ったことがあります。
実際、デバッグが済むまでの1~2時間の間、End ステートメントを使いました。
私が書いたのはその一度だけです。
End ステートメントを使ったものを公開や配布したことはありませんし今後も絶対しません。

本題ですが、、
1.
ActionFormのCommandButton1_Clickプロシージャには、
時間の掛かるループ処理があって、
ユーザーがActionFormの閉じるボタンを押した時に、MsgBoxから選択して
ActionFormのCommandButton1_Clickプロシージャにある時間の掛かるループ処理を
中断し、処理全体を中止する。
2.
続けて、
ActionFormとBasicFormを非表示にして、
BaseFormだけが表示された状態にしたい。
ということだったのでしょうか?

もしも、
ActionFormのCommandButton1_Clickプロシージャ内でのループ処理を中断する
ということだったらば、何故こちらがループという言葉を#3で持ち出すまで、
それについての説明が一切無かったのか、その理由も数通り想像していましたが、
どれも希薄に思えたので、これは無さそう、という推理でお応えしたのが#3でした。

さて、#3の補足を受けて
何が原因か10通りくらいまでは想定を拡げてみました、が、キリがないのでやめました。
今開示されている情報だけで篩に掛けても、原因となり得る数百通りの原因がありそうです。

恐らくは、
処理中断用のエスケープフラグを(PrivateやPublicで)設けて、
ActionFormのUserForm_QueryCloseのタイミングでフラグを立て、
ActionFormのCommandButton1_Clickプロシージャ内でのループ内に
  If エスケープフラグ = True Then Exit For
とか、Exit Do、みたいな、ごく普通の中断処理ぐらいまでは書けているのでしょう。
でも、もしも、これも出来ていない(知らない、解らない)ということなら、第一の原因は、これです。
その場合はこの質問の当初の主旨とは違いが大き過ぎるので、それは別件で質問してください。

次に考えなければいけないことは、
ActionFormのCommandButton1_Clickプロシージャを呼び出す方法です。
一例として、
  Call ActionForm.CommandButton1_Click
に替えて、
  Application.OnTime Now, "ProcGoRoundActionFormCommandButton1_Click"
と記し、
別途、標準モジュールに、
Private Sub ProcGoRoundActionFormCommandButton1_Click()
On Error Resume Next
  ActionForm.CommandButton1_Click
On Error GoTo 0
End Sub
と書いておきます。
こうすることで、
抜けて(終って)いなければいけない、プロシージャを事前に抜けておくことができます。
ユーザーフォームモジュールから他のユーザーフォームモジュール内のプロシージャをコールする記述
が、もしも他にも有る場合は、同様に手当てします。
そこまでする必要があるか解りませんが、対症療法的にお腹が痛い時に保険室で飲ませてくれた市販(汎用)薬的なものです。
この方法が適切か(必要か?十分か?)どうかは、やはり具体的に見てみないと判断出来ませんが、
ActionFormとBasicFormを非表示にする上では、何れにしても呼び出し方を変える必要があるでしょう。

その他、
ActionFormのCommandButton1_Clickプロシージャ内での処理について、
オブジェクトの扱い方をもう一度点検しておいた方がいいかも知れません。
もしかしたらユーザーフォームをモードレス表示にするべきだった、なんて結論(オチ)も
アルかも知れませんけれど、あれこれ想像するのにも限界はあります。
経験的な直感ですが、今回のレスで解決に結びつく確率は5%くらいかな、って思います。
その他多数の1%に満たない可能性、のどれかが正解、ってことなのでしょうから、
うまく解決に導けなくてスミマセンでした。以上で退席します。

投稿日時 - 2014-07-11 23:20:29

お礼

何度も回答頂き、本当にありがとうございます。

説明不足により、色々ご迷惑をお掛けして申し訳ありません。

ActionFormのCommandButton1_Clickで行うことが
多すぎて、そのループから抜けれないような状況でもありました。
フラグをたて、If文で抜けることも考えていたのですが
Commandbuttonをクリックしたときの動作は
色んなプロシージャを利用するため、一度に抜けることが出来ず、簡単に抜ける方法は無いか?と思い
質問させて頂きました。

If文を立てる場合、利用するループ、プロシージャなど
様々な部分にExit subをおかなければならないかと思います。

ActionForm
BasicForm
BaseForm
それぞれのフォームを終わらせるために、
If文を書いてしまうと100個以上記載しないといけないため
他にいい方法は無いかと探していました。

また、End ステートメントはあまり使わないほうがいいのですね。
ユーザーフォームを途中で終了したい場合など
楽だったため、良く使っておりました…。

色々と、文章がごちゃごちゃしていて申し訳ないです。

別に質問させていただこうと思います。
懇切丁寧に教えてくださり、ありがとうございました!

投稿日時 - 2014-07-14 11:56:48

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(4)

ANo.3

#1-2、cjです。補足欄へのレスです。

#1
大事なのは
  読込む → 表示する → 非表示にする
       → 再表示する → 非表示にする
       → 再表示する → 非表示にする
       → 再表示する → 非表示にする
       → 再表示する → 非表示にする
     ↓
  二度と使わないタイミングが来たら→インスタンスを取り消す
という順番だったり、
Load→.Show→.Hide→Unload
という順番を(プログラムの開発者として)正しく実践するか、
または、省略するなら、どこで何を省略しているのか把握しておく、ということです。
「ブックを開いたら閉じる」のと同じように
「表示したら非表示にする」一連の(一対の)処理だってことなのです。
非表示にされたユーザーフォームは目に見えませんけれども、
クラス丸ごと(イベントもプロパティもメソッドも関数もStaticな変数も)失われることなく
そのまま維持されている、ということです。
普通に閉じるボタンで閉じてしまえば、すべて失われる訳ですから大きく違います。

#2

補足欄での説明に副い
  BaseForm
   └CommandButton1
  BasicForm
   ├CommandButton1
   └ComboBox1
  ActionForm
   ├CommandButton1
   └ComboBox1
  (Sheet1 : "TEST")
というテスト用のブックを作成しました。
以下の記述で動作の確認は取れています。
> Call ActionForm.Commandbutton1_Click
この処理の内容が原因でうまくいってない可能性も少しありますけれど、
見ないと何とも言えません。
> Commandbutton1を押して、動作中であったとしても
> 終了できるように、「End」を使っていました。
> Unload についても試してみましたが、
End を使う場所ではありませんし、Unloadではなく.Hideするべきかと、、、。
> CommandButton1を押して動作中のため、
> 見た目上消えては居ますがCommandButton1の動作は継続しておりました。
意味する処が判然としませんが、
ActionFormを.Hideすれば、BasicFormのCommandButton1_Clickを抜けます。
これで解決している、というのが今の処、一番可能性の高い解釈です。
或いは、BasicFormのCommandButton1_Clickから呼び出されるループ処理を抜けられない、
ってことだったり、なんて無さそうなことも考えてみましたが、
今解っている限りでは、以下に示す方法(#1-2の主旨そのまま)
これを試して貰ってから、ですね。
テスト用のブックを作成して、この下に書いてあるままの記述を動かしてみて、
その上で未解決なら実行結果とともに詳細な補足をください。
そうしてもらわないと問題の切り分けがこちらでも出来ません。
CommandButton操作に関する処理内容はこちらで適当に仮設したものです。

' ' 〓〓〓〓〓 BaseForm モジュール 〓〓〓〓〓 8671316-3
Private Sub CommandButton1_Click()
  BasicForm.Show
End Sub
' ' 〓〓〓〓〓 BasicForm モジュール 〓〓〓〓〓 8671316-3
Private Sub CommandButton1_Click()
  Load ActionForm
  With ActionForm
    .ComboBox1.List = ComboBox1.List
    .ComboBox1.Value = ComboBox1.Value
    Call .CommandButton1_Click
    .Show
  End With
End Sub
' ' 〓〓〓〓〓 ActionForm モジュール 〓〓〓〓〓 8671316-3
Sub CommandButton1_Click()  '  ! Not Private !
  Dim sBuf As String
  With Me.ComboBox1
    sBuf = .List(0) '.Value
    .List(0) = .List(.ListIndex)
    .List(.ListIndex) = sBuf
    .ListIndex = 0
  End With
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
  If CloseMode = vbFormControlMenu Then '終了ボタンを押されていた場合は
    If FP_GetResult = True Then 'はい を押した場合の判断
      With ThisWorkbook.Worksheets("TEST")
        .Select
      End With
      Cancel = True
      Me.Hide  '  ←後から表示したものから順番に
      BasicForm.Hide  '  ←そのまま表示しておきたいものは.Hideしない
      BaseForm.Hide  '  ←    同上
      Exit Sub  '  これ←特に必要ないとは思うのですが一応、、、、。
    End If
  End If
  Application.ScreenUpdating = True  '  ←この記述の意図は解りません。
End Sub
' キャンセルするかを確認する関数
Private Function FP_GetResult() As Boolean
  If MsgBox("終了しますか?", vbInformation + vbYesNo) = vbYes Then
    FP_GetResult = True
  End If
End Function
' ' 〓〓〓〓〓 〓〓〓〓〓


> UserForm という名称でユーザーフォームは作っていなく、
> 投稿用?に名前を変えさせていただきました。
こちらの指摘の仕方も悪かったのでしょうけれど、
私が問題にしているのは、寧ろ、
UserForm という名前のユーザーフォームがあるという設問で、
投稿されていたこと、の方なのです。
質問掲示板は質問者と回答者の為にだけ存在する訳ではないので、
何も知らない閲覧者が話を鵜呑みにしてトラブった処で自己責任、ではありますが、
トラブルの原因になり兼ねない書き方を敢えて選ぶこともない訳ですし、
出来るだけ、資料として役立つスレッドだったり回答だったり、
そういうものであって欲しい、ありたい、という私の願いも含めての話でした。
認識にズレがあるようなので仕方ないです、これ以上は言いません。
あなた自身がこのカテゴリーで回答をしている人でなかったなら、
幾度かスレッドでご一緒した方でなかったなら、何も書かずに素通りしていたとは思います。
失礼しました。

#1-2補足欄へのレス、以上です。

投稿日時 - 2014-07-10 16:23:12

補足

テストプログラム、ありがとうございます。
試してみました。
ActionFormのCommandButton1_Clickの
ループから抜けられませんでした。

BaseForm →BasicForm →ActionForm(画面は切り替わらない)
この流れで試し、ActionFormで長いこと処理があるので
右上の×をクリックし終了させる。
そうすると、記載されていた
.hideが動くわけですが、
メモリ上では動作したままでした。
分かりやすいように、
ActionFormのCommandButton1_Clickが
終わったときに
Msgbox "ActionFormのボタン動作は終了しました!"

と出るようにしましたが、
何度試しても「ActionFormのボタン動作は終了しました!」
と表示されました。
やはり、CommandButton1_Clickの動作を
途中で終了させるにはUserForm_QueryCloseで
End を記入し、強制終了させるしかなさそうな気もします。

------------------------------

回答者の方々の回答しやすさ、初心者が見たときも同じものが作れるか…を考えたほうが良いということでしょうか?

資料として役立つスレッド、そのことについては
あまり考えておりませんでした。以後気をつけます。

投稿日時 - 2014-07-10 17:39:54

お礼

回答・ご忠告ありがとうございます。

投稿日時 - 2014-07-10 17:40:05

ANo.2

(2/全2葉)

整理しますが、
End も Exit Sub も今回は使いません。使い処がない筈です。
非表示は、UserForm1.Hide
もう要らないって時は、Unload UserForm1、です。
UserForm_QueryCloseイベントを使って、勝手にUnloadされないようにします。
そうすれば、ユーザーフォームが表示されているかどうか態々調べる必要もなく、
今回の課題は解決できます。
こちらからプロシージャごと提案するようなしません。
まず認識を改めて貰って、そうすると次の段階で、
諸々の設計を変更することになるのだろうと、経験的に察するものがあるからです。

最後に、非常に重要な指摘があります。余談といえば余談になりますが、、、。
ユーザーフォームのオブジェクト名として"UserForm"を用いるのは
トラブルの元ですから、やってはいけません。
例えば、UserFormを変数に格納するにはどうしますか?
  Dim objForm As UserForm
  Set objForm = UserForm
って、これ、変ですよね。
  dim objForm as userf
ぐらいまで手入力すると、普通は、候補としてUserFormがひとつだけ表示されますが、
オブジェクト名としてUserFormを使っているせいで同じ表記が2つ並んでしまいます。
これはヤバイです。
というより内部処理に悪影響を与える可能性があり、比較的重篤な障害を招くかも知れません。
昔は、そうしたコードを愉快犯的な悪意を持って掲示するような人も居たようですが、
気を付けないと疑念を持ってスルーされてしまうかも知れませんよ。
変数名、オブジェクト名、プロシージャ名、クラス名、タイプ名、、、等々、
名前を決める時は、必ず、
(同一プロジェクト内でユーザーが書いたものを含め)既存の名前を避けるようにします。
よく解らないなら、名前を付ける時は、オブジェクトブラウザで、
その名前が既に使われていないか確認する習慣をつけましょう。
手順としては、VBE画面からF2キー→オブジェクトブラウザの検索窓に名前を書き込み→検索。
これで完璧、とは言えませんが、少なくともヤバイことにはなり難いです。
前回参加したスレの質問文にも、UserFormモジュールのプロシージャ変数の名前にCountというのがありました。
今回に比べれば、殆ど影響がない間違いでしたから特に指摘せずにいましたが、
こういうのもやめた方がいいです。
自分でクラスモジュールを書く場合なんかは、普通にアリ、ですけれども。
UserFormのプロパティには、Countがないのだから、"いいんじゃね?"という方もいらっしゃるかも、ですが、
良くない、と思っている方が大多数だと私は信じています。

以上、ご参考まで。

(全2葉、完)

投稿日時 - 2014-07-10 02:00:40

補足

UserForm という名称でユーザーフォームは作っていなく、
投稿用?に名前を変えさせていただきました。

再度説明させて頂きます。
UserFormの名称を分かりやすく変更すると、
BaseForm'他のフォームを起動するためのもの
BasicForm'データを入力するためのフォーム
ActionForm'BasicFormのデータを利用して動作する。

説明のため、3つのみのフォームとさせて頂きます。
基本的どうさの流れとしては、
BaseFormでBasicFormを起動。
ユーザーがCommandButtonを押したあと、
BasicFormのデータをActionFormのコンボボックスに入れ
CommandButtonを押す。

ActionForm.Combobox1=Me.Combobox1
Call ActionForm.Commandbutton1_Click

このような流れです。

ActionFormには、前にも書いたように仕掛け?がしてあり、
×で閉じたときに、「終了しますか?」というメッセージを
表示して終了するかを促します。

Commandbutton1を押して、動作中であったとしても
終了できるように、「End」を使っていました。
Unload についても試してみましたが、
CommandButton1を押して動作中のため、
見た目上消えては居ますがCommandButton1の動作は継続しておりました。

すぐに終了する方法は、End以外には無いのでしょうか?

投稿日時 - 2014-07-10 09:45:00

お礼

回答頂きありがとうございました。

投稿日時 - 2014-07-10 09:51:47

ANo.1

(1/全2葉)

こんにちは。

まずは、基本的事項のお浚いから、、、。
「UserFormの表示/非表示」について、
  UserForm1.Show
と書いた場合、
既に読込み済の(インスタンスが確立されている)ユーザーフォームだった場合は、
文字通り、ユーザーフォームを表示するだけで、書いたこと、と、実行されること、が一致します。
が、読込みが済んでいない(インスタンスが確立されていない)ユーザーフォームだった場合は、
まず、ユーザーフォームを読み込んで、続けて、ユーザーフォームを表示するようになっていて、
  Load UserForm1
  UserForm1.Show
と、本来的には2行で書くべき2つの処理を1行に省略している、という風に考えてください。
ユーザーフォームの場合は、<ブックやシート等とは大きく違い>、
読込むまではインスタンス(実態)を持っていない<ただの設計図である>ことに留意してください。
イベントに関連付けて全体の流れを説明すると、
  Load UserForm1 = 読込む → UserForm_Initialize
  UserForm1.Show = 表示する → UserForm_Activate
  UserForm1.Hide = 非表示にする → 該当なし
  Unload UserForm1 = インスタンスを消す → UserForm_Terminate
別のユーザーフォームが、アクティベートされたりモーダル表示になった場合、
  anotheRuseRforM.Show = 自分以外のユーザーフォームを前面表示すると → UserForm_Deactivate
               表示されたユーザーフォーム側で → UserForm_Activate

これらの事項への理解を一層深めていければ、今回の課題は自ずと解決できるのではないでしょうか。

実践的な話として、
最初に読込む時の処理=Load(UserForm_Initialize)時点での処理、というのは、
大抵の場合、すべての処理が済んで、ブックを閉じるまでは、
そのままにしておいて構わない内容である筈ですから、
通常はUnload(UserForm_Terminate)せずに
(可変のパラメータに連動するにはUserForm_Activate等各種イベントで処理可能)
用が無い時は、一旦.Hideで非表示にしておいて、
つまり、読込まれた状態を保持しておいて、
また使う時に.Show(UserForm_Activate)再表示、
非表示→再表示→非表示→再表示→非表示→再表示...を繰り返し、
いよいよ使うことがない、というタイミング(通常はWorkbookを閉じる時)が来たら
Unload(UserForm_Terminate)するか、
プロジェクトの終了(リセット)を待って、勝手にインスタンスが消えるのに任せるか、
というように運用します。
なので、ユーザー操作で勝手に
<Unload(UserForm_Terminate)即ちユーザーフォームのインスタンス(実態)を消されてしまう>
ことを避ける意味で、
  Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
    If CloseMode = vbFormControlMenu Then
      Cancel = True
      Me.Hide
    End If
  End Sub
のような仕組みが用意されていることで、開発者の意図の沿った自由な設計が可能になっています。

End ステートメント、って、ユーザーフォームや、VBAProjectを終了(リセット)させる意味ですから、
というか、よっぽどのことでもない限り使うものではありません。
私は全く使わないです。
#少なくとも近現代のVBAでは、必要なものではない筈です。

#4つのユーザーフォーム、といっても、モーダル表示でお使いのようですから、
#常にひとつずつを排他的に使っているのだとすると、4つというのは少し多いような気もしますが、さておき。
  UserForm.Show
  UserFormA.Show
  UserFormB.Show
  UserFormC.Show
という記述があるなら、それらと対をなすように、
  UserForm.Hide
  UserFormA.Hide
  UserFormB.Hide
  UserFormC.Hide
という記述をを適宜用いるように考えてみて下さい。


> If UserForm.Visible = False Then
> UserForm.Show
> End If

見た目上、正しい結果を得られているのでしょうけれど、これは、ちょっと拙いです。
UserFormが既に読込まれている場合は問題ないのですが、
読込みが済んでいない(インスタンスが確立されていない)場合は、
UserForm.Visibleを取得するタイミングで
Load(UserForm_Initialize)することになってしまいます。
UserFormが既に読込まれていることが明らかな場合にしか本来はあってはならない記述です。
(.Hideされているかどうか確認する為の.Visibleプロパティです。)
処理の内容によっては問題が顕在化しないことも多いと思いますが、
期待しないタイミングで勝手に読込み処理されてしまう、ということであれば、
これは一種のバグとも言えます。
Load(UserForm_Initialize)と.Show(UserForm_Activate)の違いを理解し正しい使い分けが出来、
UserForm_Initializeイベント内でUserForm自身(または配下のコントロール)以外のオブジェクト操作は一切しないとか、
現存の記述が最終版で絶対に誰も書き換えることがないとか、条件付きで、
「まぁ差し当たり望んだ結果が得られるのだからオッケーにしよう」という割り切りの元で使うのなら構いません。
#"オッケー"という方が以外に多いので、説得力ないかも知れません?が。

> 上記で、UserFormが表示されているか確認はできますが、
> Endの前に入れようと、後に入れようと
> UserForm.showが実行されることはありません。
> だからといって、Exit Subを使うと
> UserFormB,UserFormCの動作を継続して行ってしまいます。

  UserForm.Show
  End
の順に処理した場合は、UserForm.Showを実行しますが、
直後に、VBAProjectを終了(リセット)させていますから、
<Unload(UserForm_Terminate)即ちユーザーフォームのインスタンス(実態)を消す>
ように指示しているということです。
  End
  UserForm.Show
の順に処理しようとした場合は、
End ステートメントによってVBAProjectを終了(リセット)させたからには、
それ以降の記述(UserForm.Show)が実行されることはない、
どころか、UserFormクラス自体が解放されてしまっています。

VBAでの処理中に現在表示されているユーザーフォームの数、の変動、をトレースすることは、
  MsgBox DoEvents()
などの方法で可能ですし、(※ユーザーフォーム以外にもカウントするオブジェクトがあるようですから相対値になります)
読込み済の(インスタンスを持つ)ユーザーフォームの数は、
  MsgBox UserForms.Count
とか、数の把握だけでも意図したことを実現できるようにも思いますが、
ユーザーフォームのインスタンスを勝手に作成することなく、特定のユーザーフォームが読込まれているかを調べるには、
  Function FnUserFormIsLoaded(ByVal sUfName As String) As Boolean
  Dim o As Object
    For Each o In UserForms
      If o.Name = sUfName Then
        FnUserFormIsLoaded = True
        Exit For
      End If
    Next
  End Function
などの方法も一応あります。

ただ、.Show→.Hide→.Show→.Hide ... のように運用して、
UserForm_QueryCloseの本来の使い方と組み合わせれば、
基本的には設計者の意図したように表示・非表示をハンドル出来ますから、
表示中かどうか(読込み済かどうか)調べることの必要性、というと、
私には必要とは思えません。
どうにもうまくいかないって場合でも、例えば一時的な演習とでも考えて、
各ユーザーフォームの読込み・表示をPublicな変数でフラグにしてみるというのはアリかも知れません。
そうやってデバッグを容易にしておいて慣れてくれば、
理解が深まり、やっぱり必要なかった、ってことになるように思いますので。

(次の投稿へ続く)

投稿日時 - 2014-07-10 01:58:14

補足

んー、むずかしいですね。
.Show .Hide の意味はなんとなく理解しておりました。

Loadは見えないけど、メモリ上では動作。
Unloadはメモリから削除し、画面表示も見えない。
Showはメモリ上もあるし、見える。
Hideはメモリ上あるけど、隠す。

こういった認識です。
中々むずかしくて混乱しております。

投稿日時 - 2014-07-10 09:51:34

お礼

回答いただきありがとうございます。

投稿日時 - 2014-07-10 09:29:47

あなたにオススメの質問