質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

Q&A

解決済

4回答

7872閲覧

inputboxメソッドでセルを指定させる際のキャンセル対策

barbed

総合スコア10

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

2グッド

0クリップ

投稿2019/07/12 16:08

InputBoxメソッドでセルを指定させる目的の、以下のコードについて質問です。

VBA

1 2Public Sub test() 3 Dim outputcell As Variant 4 5 'セル取得 6 outputcell = Application.InputBox("セルを選択してください", , , , , , , 8) 7 If outputcell = False Then 8 MsgBox False 9 Exit sub 10 End If 11 12 outputcell.value = "セル取得成功" 13 14End Sub 15

InputBoxメソッドの引数Typeに8を設定し、セル参照(Rangeオブジェクト)のみを入力可能にしています。
キャンセルを押されたときのことを考え、変数outputcellをVariant型にしました。

これを実行すると、セルを指定してもキャンセルを押してもoutputcellにfalseが入ってしまいます。

因みに、引数Typeに12(論理値またはセル参照)を設定すると、論理値しか指定できなくなってしまいました。

適切な値を得るには、どうしたらよいのでしょうか。

bonji, hiro.miyoshi👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

んと、、、

https://www.moug.net/tech/exvba/0150102.html
http://officetanaka.net/excel/vba/tips/tips37.htm

この辺を参考にすると、
セル範囲を変数に代入するときは、
Setステートメントを使用しなければなりません。
単に変数の型をVariant型にするだけでは、
「オブジェクト」を変数に代入できません。

つまり、Set outputcell = Application.InputBox("セルを選択してください", , , , , , , 8)
こうかかないといけません。
が、キャンセルを押すと、Falseという論理値が返ってくるので、
エラーになりますよね。
両方に対応するのは厄介ですね。

こういうときは、
On Errorステートメントを使い、エラーを回避します。

エラーを無視したときは、
変数の中身はNothingのままですので、
変数の中身がNothingかどうかで、キャンセルが押されたかの判定をします。

ExcelVBA

1Option Explicit 2 3Public Sub test() 4 Dim outputcell As Range 5 6 Application.DisplayAlerts = False '空でOKしたときの的外れなメッセージの表示を抑制 7 On Error Resume Next 8 Set outputcell = Application.InputBox("セルを選択してください", , , , , , , 8).Cells 9 On Error GoTo 0 10 Application.DisplayAlerts = True 11 12 If outputcell Is Nothing Then 13 MsgBox "キャンセルしました。" 14 Else 15 outputcell.Select 16 MsgBox outputcell.Address(False, False) & " を選択しました。" 17 End If 18End Sub

投稿2019/07/13 00:59

編集2019/07/13 01:17
mattuwan

総合スコア2167

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

VBAの「値型とオブジェクト型で代入の方法が異なる」という仕様の関係上、きれいに処理することは難しいです。

またVarType関数についても、仕様上今回の用途では使いにくいです。


対策案1 エラーで判定

キャンセルを考慮せず、セル(オブジェクト)が返されるという前提で処理を行い、
エラーが発生したらキャンセルされた、と判断する方法です。
恐らくこちらの方が一般的な方法だと思います。

On Error Resume Nextによって、代入時のエラーに対して処理を行っています。

vba

1'https://teratail.com/questions/200242 2Public Sub teratailQ200242_OnError() 3 Const XlInputBoxTypeRange = 8 4 5 Dim outputcell As Excel.Range 6 7 'セル取得 8 On Error Resume Next 9 Set outputcell = Application.InputBox("セルを選択してください", Type:=XlInputBoxTypeRange) 10 'キャンセルされた場合はBooleanが返ってくるので 11 'エラー番号91:オブジェクト変数または With ブロック変数が設定されていません。 12 'のエラーが発生する 13 If Err.Number <> 0 Then 14 MsgBox False 15 Exit Sub 16 End If 17 On Error GoTo 0 18 19 outputcell.Value = "セル取得成功" 20 21End Sub

対策案2 結果で判定

「値型とオブジェクト型で代入の方法が異なる」という仕様

に関しては、代入部分を別プロシージャに切り出し、参照渡しの引数を使うことでむりやり対処することができます(例:下記コードSetVar)。

結果を変数に入れてしまえば、後は普通に判定するだけ、となります。

この判定のときの注意として、
If inputBoxResult = False Thenとした場合、セルの値が0、空(Empty)、Falseの場合もNGになってしまいますし、エラー値や複数セル選択の場合はエラーで止まってしまいます。

If VarType(inputBoxResult) = vbBoolean Thenとした場合、VarType関数は既定のメンバーの値を見に行くため、セルにFalseが入っている場合もNGとなってしまいます。

そのため下記コードでは「Object型に適合するかどうか?」の判定関数であるIsObjectを使って判定しています(VBAのほとんどのオブジェクトはObject型に適合し、ExcelのRangeもそうであるため)。

vba

1'https://teratail.com/questions/200242 2Public Sub teratailQ200242_NotOnError() 3 Const XlInputBoxTypeRange = 8 4 5 'セル or Flase 取得 6 Dim inputBoxResult As Variant 7 SetVar(inputBoxResult) = Application.InputBox("セルを選択してください", Type:=XlInputBoxTypeRange) 8 9 If Not VBA.IsObject(inputBoxResult) Then 10 MsgBox False 11 Exit Sub 12 End If 13 14 Dim outputcell As Excel.Range 15 Set outputcell = inputBoxResult 16 17 outputcell.Value = "セル取得成功" 18 19End Sub 20 21'https://qiita.com/nukie_53/items/bde16afd9a6ca789949d#%E5%A4%89%E6%95%B0%E3%81%B8%E4%BB%A3%E5%85%A5 22Public Property Let SetVar(outVariable As Variant, inExpression As Variant) 23 If VBA.IsObject(inExpression) Then 24 Set outVariable = inExpression 25 ElseIf VBA.VarType(inExpression) = vbDataObject Then 26 Set outVariable = inExpression 27 Else 28 Let outVariable = inExpression 29 End If 30End Property

投稿2019/07/13 00:47

imihito

総合スコア2166

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

セル取得以外の場合は TanakaHiroakiさんの回答でいいのですが、
セル取得(Type引数が8)の場合はそれではダメです。
エラー処理で判断します。

vba

1Public Sub test() 2 On Error Resume Next 3 Dim outputcell As Range 4 'セル取得 5 Set outputcell = Application.InputBox("セルを選択してください", Type:=8) 6 If Err.Number <> 0 Then 7 MsgBox "キャンセルされました。" 8 Exit Sub 9 End If 10 On Error GoTo 0 11 outputcell.Value = "セル取得成功" 12End Sub

投稿2019/07/13 00:41

編集2019/07/13 00:49
hatena19

総合スコア34352

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

<回答後追記>
複数の方から、今回の質問、つまり、Application.InputBoxでセル取得(Type引数が8)の場合、キャンセルを判定するために、単にVBAのVarType関数を用いるだけでは不可能であるとのご指摘をいただきました。
下記回答を撤回します。

キャンセルについては、以下のように、VarTypeで判定する方法があります。

VBA

1' If outputcell = False Then 2 If VarType(outputcell) = vbBoolean Then 3 MsgBox False 4 Exit Sub 5 End If

投稿2019/07/12 16:23

編集2019/07/13 01:32
TanakaHiroaki

総合スコア1065

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問