このページでは、特定のユーザーフォームが開かれているか調べるコードを紹介します。
複数のフォームを連動させたり、関連処理を適切に管理するために、フォームの状態を把握することは重要です。
しかし、フォームの状態を調べる既存の関数はないため、作成したサンプルコードをパターン別に紹介します。
特定のフォームが開いているか簡単に判定することができるので、フォームを活用したツール作成の手助けになるのではないでしょうか。
コピペですぐに組み込めるようパーツ化してありますし、サンプルファイルもダウンロードできます。
ぜひ一度動作をお試しください。
サブプロシージャ版
最初は基本的なサブプロシージャ版です。
次のコードを標準モジュールにコピペし、フォーム名を変更するだけで使えます。
具体的には「”SampleForm1″」の部分を対象フォームのオブジェクト名に変更して実行してみてください。
(フォームのタイトル(Caption)ではなく、オブジェクト名を指定してくださいね。)
指定のフォームが開いていればメッセージを表示し、開いていなければ何も起こりません。
Sub 指定フォーム存在判定()
'指定名のユーザーフォームの状態判定(For Each)
'閉じるフォーム名の指定
Dim SchName As String
SchName = "SampleForm1" '◆ここにフォーム名を指定◆
'フォームが1つも開いてないときは終了
If UserForms.Count = 0 Then Exit Sub
'指定フォームの終了処理
Dim frm As Variant
For Each frm In UserForms
If frm.Name = SchName Then
MsgBox SchName & "が開いています。"
Exit Sub
End If
Next frm
End Sub
これはFor Eachでユーザーフォームコレクションを巡回し、指定フォーム名で一致判定しています。
コレクション巡回(For Each)ではなく、カウンタ変数でインデックス巡回することもできます。
Sub 指定フォーム存在判定()
'指定名のユーザーフォームの状態判定(For Next)
'閉じるフォーム名の指定
Dim SchName As String
SchName = "SampleForm1" '◆ここにフォーム名を指定◆
'フォームが1つも開いてないときは終了
If UserForms.Count = 0 Then Exit Sub
'指定フォームの終了処理
Dim i1 As Long
For i1 = 0 To UserForms.Count - 1
If UserForms(i1).Name = SchName Then
MsgBox SchName & "が開いています。"
Exit Sub
End If
Next i1
End Sub
ループはこの方法でもFor Each巡回でも問題ないですが、今回の判定は開いているフォームすべてが検査対象になるため、For Eachを使うのが適切だと思います。(以後すべてFor Eachを使います。)
サブプロシージャ版(引数指定型)
次に、同じくサブプロシージャ版で、引数を渡せるようパーツ化したものです。
Sub 指定フォーム存在判定_フォーム名引数(ByVal SchName As String)
'指定名のユーザーフォームの状態判定(For Each)
'フォームが1つも開いてないときは終了
If UserForms.Count = 0 Then Exit Sub
'指定フォームの終了処理
Dim frm As Variant
For Each frm In UserForms
If frm.Name = SchName Then
MsgBox SchName & "が開いています。"
Exit Sub
End If
Next frm
End Sub
このようにパーツ化したプロシージャがひとつあれば、次のように実行時にフォーム名を引数で渡して使い回すことができます。
Sub 指定フォーム存在判定_フォーム名引数実行()
Call 指定フォーム存在判定_フォーム名引数("SampleForm1")
End Sub
次の赤字部分がフォーム名の引数になります。
Call 指定フォーム存在判定_フォーム名引数(“SampleForm1“)
Functionプロシージャ版(完全一致)
さらに効率化するため、Functionプロシージャにしてみましょう。
Functionプロシージャはフォーム名を引数で渡すようにしてあります。
Function IsSchFormOpened(ByVal SchName As String) As Boolean
'指定名のユーザーフォームの状態判定
'フォームが1つも開かれてないときはFalse(既定値)を返す
If UserForms.Count = 0 Then Exit Function
'指定名のフォームが開いていればTrueを返す
Dim frm As Variant
For Each frm In UserForms
If frm.Name = SchName Then
IsSchFormOpened = True
Exit Function
End If
Next frm
End Function
これは指定フォームが開いていたら「True」、開いていなかったら「False」を返す関数です。
Functionプロシージャにしておくことで、次のテストコードのように判定式に組み込むなど、より柔軟に使用することができて便利です。
Sub IsSchFormOpened_テスト実行()
If IsSchFormOpened("SampleForm1") Then MsgBox "「SampleForm1」フォームが開いています。"
End Sub
Functionプロシージャ版(部分一致)
部分一致判定ができるものも掲載します。
Function LikeStrFormsCnt(ByVal SchName As String) As Long
'指定名を含むユーザーフォームの開かれている数をカウント
'フォームが1つも開かれてないときは0(既定値)を返す
If UserForms.Count = 0 Then Exit Function
'指定文字列を含むフォームがいくつ開いているかカウント
Dim frm As Variant, frmCnt As Long
For Each frm In UserForms
If InStr(frm.Name, SchName) > 0 Then
frmCnt = frmCnt + 1
End If
Next frm
'戻り値
LikeStrFormsCnt = frmCnt
End Function
これはフォーム名に指定文字列を含むフォームが開いていたら、そのフォーム数を整数で返す関数です。
実行例は次のコードを参考にしてください。
フォーム名に「Sample」をいう文字列を含むフォームが開いていたらメッセージを表示します。
Sub LikeStrFormsCnt_テスト実行()
Dim frmCnt As Long: frmCnt = LikeStrFormsCnt("Sample")
If frmCnt > 0 Then MsgBox "名前に「Sample」を含むフォームが" & frmCnt & "つ開いています。"
End Sub
Functionプロシージャ(完全一致と部分一致を選択可)
ここである程度実用的な関数も貼っておきます。
この関数をプロジェクト内(ブック内)に1つ貼っておけば、実行時に第二引数(MatchCase)の値を切り替えることで完全一致にも部分一致にも対応できます。
Trueは部分一致、Falseは完全一致です。
判定結果の戻り値は数値になります。
Function SchStrFormCnt(ByVal SchName As String, Optional MatchCase As Boolean) As Long
'指定名文字列でのユーザーフォームの状態判定(条件に一致するフォーム数を返す)
'第一引数:フォーム名の検索文字列指定(部分指定可)
'第二引数:検索文字列の一致判定指定(False=完全一致/True=部分一致)※省略=False
'フォームが1つも開かれてないときはFalse(既定値)を返す
If UserForms.Count = 0 Then Exit Function
'条件一致フォームがいくつ開いているかカウント
Dim frm As Variant, frmCnt As Long
For Each frm In UserForms
If MatchCase Then
'部分一致
If InStr(frm.Name, SchName) > 0 Then
frmCnt = frmCnt + 1
End If
Else
'完全一致
If frm.Name = SchName Then
frmCnt = 1
Exit For
End If
End If
Next frm
'戻り値
SchStrFormCnt = frmCnt
End Function
実行例は次のとおりです。
Sub SchStrFormCnt_テスト実行()
'部分一致
Dim frmCnt As Long: frmCnt = SchStrFormCnt("Sample", True)
If frmCnt > 0 Then MsgBox "名前に「Sample」を含むフォームが" & frmCnt & "つ開いています。"
'完全一致
If SchStrFormCnt("SampleForm1") > 0 Then MsgBox "「SampleForm1」フォームが開いています。"
End Sub
第二引数は省略することができ、省略した場合はFalse(完全一致)として判定します。
何パターンもコードを掲載していますが、よくわからない場合はこのコードを使っていただければと思います。
オブジェクト名で指定するサンプルコード
これまではすべて文字列型でフォーム名を指定してきました。
あまり必要ないかもしれませんが、引数をオブジェクト型で指定する方法も参考に紹介します。
前後の処理をオブジェクト型で行っているときなどはこちらのほうが集うが良いかもしれません。
Sub 指定フォーム存在判定_オブジェクト名引数(ByVal SchForm As UserForm)
'指定名のユーザーフォームの状態判定(For Each)
'フォームが1つも開いてないときは終了
If UserForms.Count = 0 Then Exit Sub
'指定フォームの終了処理
Dim frm As UserForm
For Each frm In UserForms
If TypeName(frm) = TypeName(SchForm) Then
MsgBox TypeName(SchForm) & "が開いています。"
Exit Sub
End If
Next frm
End Sub
ポイントはTypeName関数でフォーム名を取得しているところです。
フォーム名をオブジェクト型変数で取得するときは、例えばfrm.CodeNameのような一般的なオブジェクト名の取得方法は使えません。
呼び出し方は次を参考にしてください。
Sub 指定フォーム存在判定_オブジェクト名引数実行()
Call 指定フォーム存在判定_オブジェクト名引数(SampleForm1)
End Sub
文字列型で指定した場合との違いがわかるでしょうか?
引数の指定文字列が「”SampleForm1″」ではなく、「SampleForm1」になっていますね。
前後の処理をオブジェクト型で行っている場合で、さらにそのオブジェクト変数等で処理したいときは、こういった方法が必要になる場合もあり得ます。
参考程度にお知り置きください。
フォームを閉じる処理の参考
このページで紹介したコードの使い道で、特定のフォームを閉じたいときに使うことを思いついた方はいないでしょうか?
結論から言うと、特定のフォームを閉じるとき、ほとんどの場合で開いているかを確認する必要はありません。
単純に「Unload “フォーム名”」で大丈夫です。
理由は、Unloadするフォームが開いてなかったとしてもエラーにならないから。
つまり、残念ながら今回紹介してきたコードはこのパターンでは不要です。
フォームの状態判定が必要になるのは、例えば「Aフォームが開いているときはBフォームを閉じれないようにしたい」など、複数のフォームを連携制御したいときです。
まとめ
今回は、特定のユーザーフォームが開いているか調べる方法を、いくつかのパターンに分けて紹介させていただきました。
目的によりますが、複数のユーザーフォームを連携させるときは、こういった処理も必要になると思います。
コードも短く扱いやすいので、必要になったときはぜひご利用ください。
すべてのフォームを閉じるサンプルコード(おまけ)
すべてのフォームを閉じるコードはとても簡単なので、おまけに掲載しておきます。
それではまた。
Sub すべてのフォームを閉じる()
Dim frm As UserForm
For Each frm In UserForms
Unload frm
Next
End Sub
コメント