VBAの勉強を始めてみた

色々試しています。

InputBoxのキャンセル判定について(Tips-4)

VBAの勉強を始めて、これまでに学んだことや、思いついたアレやコレをメモっておきます。

 

今回は、InputBoxでキャンセルを押された場合の判定についてです。

InputBoxでキャンセルを押されたときに、何らかの処理(例えばプロシージャを終了するとか)をさせるために、下記のような条件分岐を入れることがあると思います。

Sub test()
    tmp = InputBox("何か入力して下さい")
        If tmp = "" Then
            Exit Sub
        End If
End Sub

 

InputBox関数でキャンセルを押された場合の戻り値は、空白(長さ0の文字列)です。
なので、変数の中身が空白であった場合は、条件分岐で Exit Sub をさせるわけです。

では、戻り値に空白そのものを使用したい場合はどうでしょう?
上記のコードでInputBoxを空白のままでOKしても、結局、変数の中身は空白であり、キャンセルと同じく Exit Sub されてしまいます。

 

このようなケースでは、InputBox関数ではなく、InputBoxメソッドを使用すると便利です。

InputBoxメソッドでキャンセルを押された場合は、戻り値にBoolean型の False が返ってきますので、変数の型が Variant であれば、下記のように条件分岐させることができます。

Sub test()
    tmp = Application.InputBox("何か入力して下さい")
        If TypeName(tmp) = "Boolean" Then
            Exit Sub
        End If
End Sub

 

TypeName関数で変数のデータ型を調べ、Boolean型であれば条件分岐で Exit Sub するようにしています。

では、変数をVariant型ではなく、数値型や文字列型などで宣言した場合はどうなるでしょうか?
やってみましょう。
変数を数値型にして、キャンセルした場合は False に該当する数値の 0 が入るので、

Sub test()
    Dim tmp As Integer
    
    tmp = Application.InputBox("何か入力して下さい")
        If tmp = 0 Then
            Exit Sub
        End If
End Sub

 

のように条件分岐させることができます。

ではでは、変数を文字列型にした場合はどーでしょう?
変数を文字列型にして、キャンセルした場合は False という文字列が入るので、

Sub test()
    Dim tmp As String
    
    tmp = Application.InputBox("何か入力して下さい")
        If tmp = "False" Then
            Exit Sub
        End If
End Sub

 

のように条件分岐させることができます。

ただし、上記二つの例は 0 という数値と、False という文字列が戻り値として扱えなくなってしまうため、理由がなければ、変数は Variant で宣言すれば良いでしょう。

 

ちなみに、InputBoxメソッドはモードレスなので、入力する数値や文字列をセルから選ぶこともできます。

  • モードレス:ダイアログボックスが表示されている間、ダイアログボックス以外の操作もできる状態
  • モーダル:ダイアログボックスが表示されている間、ダイアログボックス以外の操作ができない状態(InputBox関数で表示されるダイアログボックスはモーダル)

 

ダイアログボックスが表示されている状態で、セルを範囲選択すれば、Range(セル範囲)を入力することもできます。
しかし、戻り値をRange型(要するにオブジェクト)にする場合は、必ず先頭に Set をつけて、

Set tmp = Application.InputBox(prompt:="何か入力して下さい", Type:=8)

のように、書く必要があるため、この時点でBoolean型のデータは代入することができなくなってしまいます。
何を言いたいかというと、この Set がついていると、キャンセルしたときに「オブジェクトが存在しないぜ」ってことで、エラーが発生するってことです。

うーん・・・・・・。じゃあ、キャンセル判定どーしようか?

エラーになるっていうことは、変数は空っぽのままのハズなので、次のようにしてみましょう。

Sub test()
    Dim tmp As Range
    
    Set tmp = Application.InputBox(prompt:="何か入力して下さい", Type:=8)
        If tmp Is Nothing Then
            Exit Sub
        End If
End Sub

 

tmp Is Nothing で、オブジェクト変数が空っぽ(Nothing)ならば、条件分岐で Exit Sub させます。

 

え?・・・・・・なんか足りない?

そもそも、エラーが発生した行で処理が止まってしまうので、以下の記述をさらに追加する必要があります。

Sub test()
    Dim tmp As Range
    
    On Error Resume Next
    
    Set tmp = Application.InputBox(prompt:="何か入力して下さい", Type:=8)
        If tmp Is Nothing Then
            Exit Sub
        End If
        
    On Error GoTo 0
    
End Sub

 

On Error Resume Next から下の行は、エラーが発生しても、エラーを無視してそのまま処理を続けるようになります。

そして、On Error GoTo 0 で、On Error Resume Next の効果を解除します。

 

これで、Range型の場合のキャンセル判定もできるようになりましたね! 

 

※Range型のキャンセル判定のケースは インストラクターのネタ帳 というサイトを参考にさせていただきました。