Handle cancellation of InputBox to select range

后端 未结 6 1848
小蘑菇
小蘑菇 2020-12-10 06:20

I have the following piece of code:

dim selectRange as Range
Set selectRange = Application.InputBox(\"Select your range\", \"Hello\", , , , , , 8)

相关标签:
6条回答
  • 2020-12-10 06:28

    I have found that checking for the "Object required" error that you mentioned is one way of handling a cancel.

    On Error Resume Next
    dim selectRange as Range
    ' InputBox will prevent invalid ranges from being submitted when set to Type:=8.
    Set selectRange = Application.InputBox("Select your range", "Hello", , , , , , 8)
    ' Check for cancel: "Object required".
    If Err.Number = 424 Then
        ' Cancel.
        Exit Sub
    End If
    On Error GoTo 0
    
    0 讨论(0)
  • 2020-12-10 06:29

    I'm late to the party here but this was the only place I could find that explained why I was having trouble just checking my variable for nothing. As explained in the accepted answer, the vbCancel on a range object isn't handled the same way as a string object. The error must be caught with an error handler.

    I hate error handlers. So I segregated it to its own function

    Private Function GetUserInputRange() As Range
        'This is segregated because of how excel handles cancelling a range input
        Dim userAnswer As Range
        On Error GoTo inputerror
        Set userAnswer = Application.InputBox("Please select a single column to parse", "Column Parser", Type:=8)
        Set GetUserInputRange = userAnswer
        Exit Function
    inputerror:
        Set GetUserInputRange = Nothing
    End Function
    

    Now in my main sub I can

    dim someRange as range
    set someRange = GetUserInputRange
    if someRange is Nothing Then Exit Sub
    

    Anyhow this is not the same as the accepted answer because it allows the user to only handle this error with a specific error handler and not need to resume next or have the rest of the procedure handled the same way. In case anyone ends up here like I did.

    0 讨论(0)
  • 2020-12-10 06:32

    While this question is a bit older I still want to show the proper way to do it without errors. You can do it either to it via function or with a sub.

    Your main procedure is something like this:

    Sub test()
      Dim MyRange As Range
    
      testSub Application.InputBox("dada", , , , , , , 8), MyRange 'doing via Sub
      Set MyRange = testFunc(Application.InputBox("dada", , , , , , , 8)) ' doing via function
    
      If MyRange Is Nothing Then
        Debug.Print "The InputBox has been canceled."
      Else
        Debug.Print "The range " & MyRange.Address & " was selected."
      End If
    End Sub
    

    the Sub-way (funny) would be:

    Sub testSub(ByVal a As Variant, ByRef b As Range)
      If TypeOf a Is Range Then Set b = a
    End Sub
    

    And the function would look like:

    Function testFunc(ByVal a As Variant) As Range
      If TypeOf a Is Range Then Set testFunc = a
    End Function
    

    Now simply use the way you like and delete the unused line.

    If calling a sub or a function you do not need to Set the parameter. That said, it doesn't matter if the InputBox returns an object or not. All you need to do, is to check if the parameter is the object you want or not and then act accordingly to it.

    EDIT

    Another smart way is using the same behavior with a collection like this:

    Sub test()
      Dim MyRange As Range
      Dim MyCol As New Collection
    
      MyCol.Add Application.InputBox("dada", , , , , , , 8)
      If TypeOf MyCol(1) Is Range Then Set MyRange = MyCol(1)
      Set MyCol = New Collection
    
      If MyRange Is Nothing Then
        Debug.Print "The inputbox has been canceled"
      Else
        Debug.Print "the range " & MyRange.Address & " was selected"
      End If
    End Sub
    

    If you still have any questions, just ask ;)

    0 讨论(0)
  • 2020-12-10 06:34

    This is a problem when selection a range with an inputbox. Excel returns an error before the range is returned, and it carries this error on when you press cancel.

    You should therefore actively handle this error. If you don't want anything to happen when you press cancel, you can just use the code like this:

    Sub SetRange()
        Dim selectRange As Range
    
        On Error Resume Next
            Set selectRange = Application.InputBox("Select your range", "Hello", , , , , , 8)
        Err.Clear
        On Error GoTo 0
    End Sub 
    
    0 讨论(0)
  • 2020-12-10 06:41

    I went with a cleaner solution:

    Dim InputValue As Range
    On Error Resume Next
    Set InputValue = Application.InputBox("Select Range","Obtain Range", Type:=8)
    Err.Clear
    If InputValue Is Nothing Then
        GoTo ExitApp:
    End If
    

    This will clear the error message and catch the "nothing" value returned to InputValue. Usefully, this doesn't interrupt a submission of no information, which Excel just loops back to requesting input automatically, but the user may need to add additional error handling for bad data entry.

    Down code, add:

    ExitApp:
        Exit Sub
    

    For exiting, which can be usefully shared between multiple input cancel handlers.

    0 讨论(0)
  • 2020-12-10 06:45

    If I use Dirks second answer inside a for loop and I want to exit my sub, it is not enough to execute an Exit Sub inside his IF statement
    I found that if I use Exit Sub standalone inside a for loop, I will not exit my sub in all cases, however, in most cases only exit the for loop.

    Here you have Dirks code

    EDIT

    Another smart way is using the same behavior with a collection like this:

     Sub test()
      Dim MyRange As Range
      Dim MyCol As New Collection
    
      MyCol.Add Application.InputBox("dada", , , , , , , 8)
      If TypeOf MyCol(1) Is Range Then Set MyRange = MyCol(1)
      Set MyCol = New Collection
    
      If MyRange Is Nothing Then
        Debug.Print "The input box has been canceled"
      Else
        Debug.Print "the range " & MyRange.Address & " was selected"
      End If
     End Sub
    

    If you still have any questions, just ask ;)

    Here is what I made to work as a example:

    Sub test()
      Dim i as Integer
      Dim boolExit as Boolean
      Dim MyRange As Range
      Dim MyCol As New Collection
      boolExit = False
    
      For i = 1 To 5 Then
        MyCol.Add Application.InputBox("dada", , , , , , , 8)
        If TypeOf MyCol(1) Is Range Then Set MyRange = MyCol(1)
        Set MyCol = New Collection
    
        If MyRange Is Nothing Then
          Debug.Print "The inputbox has been canceled"
          boolExit = True
          Exit Sub
        Else
          Debug.Print "the range " & MyRange.Address & " was selected"
        End If
      Next i
    
      If boolExit = True Then Exit Sub 'Checks if Sub should be exited
    
      Debug.Print "Program completed"      
    End Sub
    

    If you press cancel at anytime in the five runs, the Sub is shutdown with the above code and you will never see Program completed printed.

    However if you remove boolExit from the above, the code after the For loop is still being run if you press cancel in any of the 1+ runs and you will see Program completed even when that is not true.

    0 讨论(0)
提交回复
热议问题