Проблема с IsError?. BASIC runtime error. '91' Object variable not set.

Автор Al_Ex, 24 мая 2017, 11:21

0 Пользователи и 1 гость просматривают эту тему.

Al_Ex

И снова я со своим мегамакросом :)
В принципе запустил его в Либре, в дебажном режиме довольно далеко забежал, но споткнулся неожиданно на простой проверке в одной из функций.
Вся функция, написанная на VBA in Excel:

Public Function strCheckActiveCellValue() As String
   If Left(ActiveCell.Formula, 1) = "=" Then
       If ActiveCell.Value = "" Then
           strCheckActiveCellValue = """"""
       Else
           strCheckActiveCellValue = Right(ActiveCell.Formula, Len(ActiveCell.Formula) - 1)
       End If
   Else
If IsError(ActiveCell.Value) Then
           strCheckActiveCellValue = ActiveCell.Text
       Else
           If IsEmpty(ActiveCell.Value) Then
               strCheckActiveCellValue = ActiveCell.Value
           Else
               strCheckActiveCellValue = ActiveCell.Text
           End If
       End If
   End If
End Function


Падает на

If IsError(ActiveCell.Value) Then


Выдает ошибку
BASIC runtime error. '91'
Object variable not set.

Погуглив, так и не понял в чем проблем - тут нужен другой синтаксис? Хотя аналога не нашел. Или проблема в чем-то другом?

mikekaganski

#1
Сначала проверяйте на IsEmpty. IsError ожидает проинициализированную переменную (Value). Вообще, проверять значение до того, как вообще установить, что значение есть - это логическая ошибка. Хотя в Бейсике и не такое бывает :)

Хе. Только заметил, что IsError делает то же самое, что и не-IsEmpty. Так что IsError тут просто вообще лишний :)
С уважением,
Михаил Каганский

Al_Ex

Наверное я еще не разобрался в физике процесса.
Я же проверяю содержимое активной ячейки. Активная ячейка определяется другими методами, где устанавливается курсор в определенную позицию, и мне нужно знать ее содержимое. Даже если ячейка пустая, это тоже корректный результат, который обрабатывается отдельно и будет участвовать в дальнейших расчетах. Как в таком случае работает IsError, он не понимает, что нужно проверить содержимое активной ячейки?

mikekaganski

IsError вообще ничего не понимает, это не человек.

В эту функцию передаётся переменная (ActiveCell.Value). Не ячейка, а переменная в объекте. Она, как видно из кода, может быть пустой (IsEmpty), то есть не содержать значения. IsError проверяет, является ли значение переменной ошибкой. То есть она ожидает, что значение есть. Да, теоретически можно в начало реализации этой функции запихать проверку на пустую переменную, но так не сделали.

Всегда *сначала* проверяется, есть ли значение (IsEmpty), если есть - тогда уже какое оно (IsError, IsNull, etc).
С уважением,
Михаил Каганский

rami

Цитата: Al_Ex от 24 мая 2017, 10:05Как в таком случае работает IsError, он не понимает, что нужно проверить содержимое активной ячейки?
А что, содержимое ячейки "объект" ??? и этот объект может быть ошибкой?

rami

Если содержимое ячейки совсем уж не известно, наверно, лучше использовать следующие функции проверки типа:
TypeName(variable)   'Возвращает имя типа объекта в виде строки.
или
VarType(variable)    'Возвращает тип переменной в виде целого числа.

Al_Ex

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

Sub RecordValueToStatusAndDifferentErCell()
    Dim strRefFirstCell As String                                                                                               'Declare variable for reference of first cell
    Dim strRefSecondCell As String                                                                                              'Declare variable for reference of second cell
    Dim strRefThirdCell As String                                                                                               'Declare variable for reference of third cell
       
    ActiveCell.Offset(0, -3).Select                                                                                             'Activate cell with from "B" cell
    strRefFirstCell = ActiveCell.Address(RowAbsolute:=False, ColumnAbsolute:=False)                                             'Assigned ref by first cell to the variable
    ActiveCell.Offset(0, 2).Select                                                                                              'Activate cell with from "D" cell
    strRefSecondCell = ActiveCell.Address(RowAbsolute:=False, ColumnAbsolute:=False)                                            'Assigned ref by first cell to the variable
    ActiveCell.Offset(0, 1).Select                                                                                              'Activate cell with from "E" cell
    strRefThirdCell = ActiveCell.Address(RowAbsolute:=False, ColumnAbsolute:=False)                                             'Assigned ref by first cell to the variable
        If IsError(ActiveCell.Value) Then                                                                                       'If active cell value is error
            ActiveCell.Offset(0, 1).Select                                                                                      'Activate cell in "F" column
            Call PassFailAccordingWithLocalePart1(strRefFirstCell, strRefSecondCell, strRefThirdCell)
        Else                                                                                                                    'If active cell value isn't error
            Call PassFailAccordingWithLocalePart2(strRefFirstCell, strRefSecondCell, strRefThirdCell)
        End If
    End If
End Sub


Как здесь нужно переписать? Так не работает:
If IsError(IsEmpty(ActiveCell.Value)) Then
или
If IsError(TypeName(ActiveCell.Value)) Then   
Чувствую, что бред написал, но не понимаю, как это правильно обработать.

rami

Цитата: Al_Ex от 24 мая 2017, 11:22Как здесь нужно переписать? Так не работает:
 If IsError(IsEmpty(ActiveCell.Value)) Then
или
 If IsError(TypeName(ActiveCell.Value)) Then   
Чувствую, что бред написал, но не понимаю, как это правильно обработать.
Если бы была функция IsBred(), она бы всегда возвращала значение "абсолютная правда" ;D ;D ;D


1. IsEmpty(ActiveCell.Value) возвращает true или false, в любом случае это не годится для IsError()
2. TypeName(ActiveCell.Value) возвращает строковое значение, что тоже не годится для IsError()

Мне кажется, вы хотите "приделать пропеллер к чемодану без ручки"  ;D вместо того, чтобы выкинуть его и сделать что-нибудь подходящее на замену.

Al_Ex

Основная идея была такая: проверить содержимое ячейки, и если это ошибка, то выполнить определенные действия.
В качестве замены был найден вариант:


Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
  IsInArray = (UBound(Filter(arr, stringToBeFound, True, vbTextCompare)) > -1)
End Function



Sub ErCell()
    Dim errorArray As Variant
    errorArray = Array("#N/A", "#DIV/0!", "#VALUE!", "#NAME?", "#NULL!", "#REF!", "#NUM!")
    If IsInArray(ActiveCell.Text, errorArray) Then                                                                         
        ActiveCell.Offset(0, 1).Select                                                                                       
        Call Func1(strRefFirstCell, strRefSecondCell, strRefThirdCell)
    Else                                                                                                                       
        Call Func2(strRefFirstCell, strRefSecondCell, strRefThirdCell)
    End If
End Sub


В Экселе такой код работает, правда не совсем корректно. Если в ячейке попадается цифра 0, то она матчится с ошибкой #DIV/0!, в которой есть эта цифра. Поигрался разными вариантами работы с функцией Filter, но так и не нашел варианта, чтобы искалось совпадение целиком.
А в Либре этот код вообще не хочет работать и на первой же итерации возникает ошибка: "BASIC runtime error. '35' Filter".
Как еще можно обыграть эту ситуацию?

Al_Ex

Цитата: rami от 24 мая 2017, 12:29
Если содержимое ячейки совсем уж не известно, наверно, лучше использовать следующие функции проверки типа:
TypeName(variable)   'Возвращает имя типа объекта в виде строки.
или
VarType(variable)    'Возвращает тип переменной в виде целого числа.


Тоже хороший вариант, и простой, но...
В Экселе такая конструкция работает

   If TypeName(ActiveCell.Value) = "Error" Then

И оно действительно возвращало тип Error если находило ошибку.
В Либре какой бы тип данных не находился в ячейке, все время возвращается тип Double.
Если заменить на ActiveCell.Text, то соответственно всегда будет тип String.
Получается в случае нахождения ошибки тип определяется неверно и дальнейшие действия не проходят.