Обработка отмены InputBox для выбора диапазона

У меня есть следующий фрагмент кода:

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

Когда пользователь выбирает Отменить приглашение InputBox, он возвращает error of Object not set.

Я пытался использовать тип переменной Variant, но не могу с этим справиться. В случае отмены возвращает False, а в случае выбора диапазона возвращает Range of InputBox.

Как я могу избежать этой ошибки?


person Jeremy Newton    schedule 26.10.2013    source источник
comment
Проблема не в этих двух строках кода, а скорее в строках, следующих за ними. Покажите нам эти строки.   -  person RBarryYoung    schedule 26.10.2013


Ответы (6)


Это проблема при выборе диапазона с полем ввода. Excel возвращает ошибку до того, как будет возвращен диапазон, и продолжает эту ошибку, когда вы нажимаете кнопку «Отмена».

Поэтому вы должны активно обрабатывать эту ошибку. Если вы не хотите, чтобы при нажатии кнопки «Отмена» ничего не происходило, вы можете просто использовать такой код:

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 
person Netloh    schedule 26.10.2013
comment
Спасибо за это, я думаю, что это отстойно обрабатывать ошибки на vbcancel вот так, но другого выбора нет. - person Raystafarian; 14.04.2016

Хотя этот вопрос немного старше, я все же хочу показать правильный способ сделать это без ошибок. Вы можете сделать это либо с помощью функции, либо с помощью сабвуфера.

Ваша основная процедура выглядит примерно так:

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

способ Sub (забавный) будет таким:

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

И функция будет выглядеть так:

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

Теперь просто используйте так, как вам нравится, и удалите неиспользуемую строку.

При вызове подпрограммы или функции вам не нужно Set параметр. Тем не менее, не имеет значения, возвращает ли InputBox объект или нет. Все, что вам нужно сделать, это проверить, является ли параметр тем объектом, который вам нужен, а затем действовать в соответствии с ним.

ИЗМЕНИТЬ

Другой разумный способ — использовать такое же поведение с такой коллекцией:

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

Если у вас еще остались вопросы, спрашивайте ;)

person Dirk Reichel    schedule 31.05.2016
comment
Ссылаясь на Метро (смешно). Я думаю, что это может вызвать проблему с одной ячейкой. Поскольку поле ввода кэшируется в варианте, оно будет преобразовано и потеряет тип диапазона. Ведь использование Set b = a невозможно. - person Viktor West; 01.09.2020

Я опоздал на вечеринку, но это было единственное место, где я смог найти объяснение, почему у меня возникли проблемы с простой проверкой моей переменной. Как объясняется в принятом ответе, vbCancel в объекте диапазона не обрабатывается так же, как строковый объект. Ошибка должна быть перехвачена обработчиком ошибок.

Я ненавижу обработчики ошибок. Поэтому я выделил его для своей собственной функции

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

Теперь в моем основном сабе я могу

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

В любом случае это не то же самое, что принятый ответ, потому что он позволяет пользователю обрабатывать эту ошибку только с помощью определенного обработчика ошибок и не требует resume next или обработки остальной части процедуры таким же образом. На случай, если кто-нибудь окажется здесь, как я.

person Raystafarian    schedule 14.04.2016

Я обнаружил, что проверка ошибки «Требуется объект», о которой вы упомянули, является одним из способов обработки отмены.

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
person Ken Love    schedule 14.10.2015

Я пошел с более чистым решением:

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

Это очистит сообщение об ошибке и уловит пустое значение, возвращаемое в InputValue. Полезно то, что это не прерывает отправку информации, которая Excel просто возвращается к автоматическому запросу ввода, но пользователю может потребоваться добавить дополнительную обработку ошибок для ввода неправильных данных.

Код вниз, добавьте:

ExitApp:
    Exit Sub

Для выхода, который можно с пользой разделить между несколькими обработчиками отмены ввода.

person Prometheus2508    schedule 18.08.2020
comment
мне нравится это решение - person Friedrich; 30.09.2020

Если я использую второй ответ Дирка внутри цикла for и хочу выйти из своего подпрограммы, недостаточно выполнить Exit Sub внутри его оператора IF
Я обнаружил, что если я использую автономный Exit Sub внутри цикла for, я не выходить из моей подпрограммы во всех случаях, однако в большинстве случаев выходит только из цикла for.

Здесь у вас есть код Диркса

ИЗМЕНИТЬ

Другой разумный способ — использовать такое же поведение с такой коллекцией:

 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

Если у вас еще остались вопросы, спрашивайте ;)

Вот что я сделал для работы в качестве примера:

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

Если вы нажмете «Отмена» в любой момент из пяти прогонов, сабвуфер выключится с помощью приведенного выше кода, и вы никогда не увидите напечатанного Программа завершена.

Однако, если вы удалите boolExit из приведенного выше, код после цикла For все еще будет выполняться, если вы нажмете «Отмена» в любом из 1+ запусков, и вы увидите Программа завершена, даже если это не так.

person mwahlgreen    schedule 04.01.2019