VBA: функция выдает ошибку времени выполнения «424»: объект требует ошибки при вызове

У меня есть две основные функции, первая — search_bank. Он просматривает столбцы Credits, Type и store, ячейка за ячейкой и выясняет, есть ли у нас совпадение или нет. Если есть совпадение, он возвращает True и в качестве побочного эффекта изменяет цвет соответствующей ячейки.

Второй sub я использую для тестирования первой функции. Проблема, с которой я столкнулся, заключается в том, что я получаю сообщение Ошибка выполнения "424": требуется объект без указания места возникновения проблемы.

Вот первая функция:

Function search_bank(Store As String, amount As Double, Amex As Boolean) As Boolean
    Dim m_store As Range
    Dim m_type As Range
    Dim Credit_Amt_Col As Range

    Set m_store = bank_sheet.Range("1:1").Find("M_STORE")
    Set m_type = bank_sheet.Range("1:1").Find("M_TYPE")
    Set Credit_Amt_Col = bank_sheet.Range("1:1").Find("Credit Amt")

    search_bank = False
    Dim i As Long
    For i = 1 To 9000
        If Not search_bank Then
            Dim store_cell As Range
            Dim type_cell As Range
            Dim credit_cell As Range

            Set store_cell = Worksheets(2).Cells(i, m_store.Column)
            Set type_cell = Worksheets(2).Cells(i, m_type.Column)
            Set credit_cell = Worksheets(2).Cells(i, Credit_Amt_Col.Column)

            If InStr(UCase(store_cell.Value), UCase(Store)) > 0 And credit_cell.Value = amount Then
                If store_cell.Interior.ColorIndex <> 46 Then
                    If Amex And InStr(UCase(type_cell.Value), UCase("amex deposit")) Then
                        store_cell.Interior.ColorIndex = 46
                        search_bank = True

                    End If
                    If Not Amex And InStr(UCase(type_cell.Value), UCase("Credit Card Deposit")) Then
                        store_cell.Interior.ColorIndex = 46
                        search_bank = True

                    End If
                End If
            End If
        End If
    Next i

End Function

а вот тестер:

Sub Tester()
    Dim x As Boolean
    x = search_bank("ctc", 38.4, True)
    Debug.Print (x)
End Sub

Я попытался использовать «набор» на тестере:

Sub Tester()
    Dim x As Boolean
    Set x = search_bank("ctc", 38.4, True)
    Debug.Print (x)
End Sub

И даже объявление переменной перед ее передачей в тестер (я не очень привык к VBA, но на мгновение я подумал, что это настолько древнее, что нужно было объявить вещи до того, как они будут переданы)

Sub Tester()
    Dim x As Boolean
    Dim store As String
    Dim Amount As Double
    Dim amex As Boolean
    store = "ctc"
    Amount = 38.4
    amex = True
    x = search_bank(store, Amount, amex)
    Debug.Print (x)
End Sub

person Ryan Francis    schedule 16.03.2017    source источник
comment
Когда вы получите ошибку времени выполнения, выберите параметр «Отладка» и используйте F8 для пошагового выполнения кода, пока не увидите строку, в которой ошибки.   -  person David Zemens    schedule 16.03.2017
comment
Где/когда/как вы объявляете bank_sheet?   -  person BruceWayne    schedule 16.03.2017
comment
Кроме того, убедитесь, что результат ваших трех методов Find возвращает допустимые объекты. Если значения не найдены в строке 1, они вернут Nothing, что вызовет эту ошибку позже в вашем коде.   -  person David Zemens    schedule 16.03.2017
comment
Range.Find может вернуть Nothing. Вы должны проверить возвращаемые значения.   -  person Comintern    schedule 16.03.2017
comment
- Шаг через это здорово! Я нашел, где была проблема. - Это было потому, что я не объявлял bank_sheet. Я почему-то предположил, что это глобально. Я такой глупый.   -  person Ryan Francis    schedule 16.03.2017
comment
Ни один из них на самом деле не является ответом, просто комментарии/предложения :)   -  person David Zemens    schedule 16.03.2017
comment
Кроме того, если вы только открываете F8 для пошагового выполнения кода, прочтите это и добавьте в закладки cpearson.com /excel/ОтладкаVBA.aspx   -  person David Zemens    schedule 16.03.2017
comment
@DavidZemens Вы поняли .. Может ли кто-нибудь из вас опубликовать свои комментарии в качестве ответа, чтобы я мог пометить этот вопрос как решенный?   -  person Ryan Francis    schedule 16.03.2017
comment
Технически это был бы ответ Брюса. Или вы также можете ответить на свой вопрос :)   -  person David Zemens    schedule 16.03.2017
comment
@RyanFrancis FWIW у вас есть бесплатный глобальный объект рабочего листа. Посмотрите на окно инструментов Project Explorer; узлы рабочего листа отображаются как Sheet1 (Sheet1) — это CodeName (WorksheetName), где CodeName — это объектная переменная Worksheet глобальной области видимости, которую вы получаете бесплатно. Вы можете изменить его имя в окне инструментов properties (F4), изменив свойство (Name).   -  person Mathieu Guindon    schedule 16.03.2017
comment
@Mat'sMug Это потрясающе! и очень актуально в данной ситуации.   -  person Ryan Francis    schedule 16.03.2017
comment
@BruceWayne Не могли бы вы опубликовать свой комментарий в качестве ответа, чтобы я мог пометить это как решенное. Проблема заключалась в том, что я не объявлял bank_sheet.   -  person Ryan Francis    schedule 16.03.2017


Ответы (2)


Под вашим ОП есть много хороших комментариев, а также ответ @BrandonBarney, но вот мои два цента:

Cent one: самое главное, что я вижу, это то, что вы никогда не объявляете blank_sheet, но пытаетесь использовать его при установке объекта диапазона. Вот откуда ваша ошибка. Он хочет сделать Range("1:1").Find("M_STORE"), но не знает, что такое bank_sheet.

Два цента: быстрый способ сообщить вам об этом — всегда используйте Option Explicit в начале кода. Это гарантирует, что любая переменная, которую вы используете, объявлена ​​явно. То есть:

Option Explicit

Function search_bank(Store As String, amount As Double, Amex As Boolean) As Boolean
    Dim m_store As Range
    Dim m_type As Range
    Dim Credit_Amt_Col As Range

    ''''' New code here: ''''''
    Dim bank_sheet as Worksheet
    Set bank_sheet = Worksheets("Bank Sheet") ' change to whatever the name is.
    '''''''''''''''''''''''''''
    Set m_store = bank_sheet.Range("1:1").Find("M_STORE")
    Set m_type = bank_sheet.Range("1:1").Find("M_TYPE")
    Set Credit_Amt_Col = bank_sheet.Range("1:1").Find("Credit Amt")
    ' etc. etc.

Option Explicit также поможет, если вы случайно сделаете опечатку. Поэтому, если вы когда-либо делали bank_sheeet.Range("A:A"), он выдаст ошибку и попросит вас объявить bank_sheeet. Или, конечно, вы поймете, что это опечатка, а затем просто исправите ее.

Бонусный цент: вы можете сэкономить несколько строк, объединив свои Dims:
Dim m_store as Range, m_type as Range, Credit_Amt_Col as Range могут быть в одной строке.

(Примечание. При выполнении Dim m_store, m_type, Credit_Amt_Col as Range не всем трем будет присвоен тип Range. Это сделает m_store и m_type типом Variant, поскольку он не объявлен. В этом случае только Credit_Amt_Col будет Range , Так что вам все равно придется явно указать тип для каждой переменной).

person BruceWayne    schedule 16.03.2017

Я бы написал это как комментарий, если бы мог, но не могу. Поэтому я знаю, что это не решит проблему напрямую, но поможет в отладке. Смотри ниже:

Function search_bank(Store As String, amount As Double, Amex As Boolean) As Boolean
Dim m_store As Range
Dim m_type As Range
Dim Credit_Amt_Col As Range

' It is always best to check the inverse of an object before setting
' setting an object variable to the target object. In this case
' I check to make sure each range can be found, and if not, I
' debug.print which variable cannot be set.

Set m_store = bank_sheet.Range("1:1").Find("M_STORE")
Set m_type = bank_sheet.Range("1:1").Find("M_TYPE")
Set Credit_Amt_Col = bank_sheet.Range("1:1").Find("Credit Amt")

If m_store is Nothing then Debug.Print "m_store is nothing"
If m_type is Nothing then Debug.Print "m_type is nothing"
If Credit_Amt_Col is Nothing then Debug.Print "Credit_Amt_Col is nothing."

search_bank = False
Dim i As Long
For i = 1 To 9000
    If Not search_bank Then
        Dim store_cell As Range
        Dim type_cell As Range
        Dim credit_cell As Range

        ' Use the inverse method above on these three items as well.
        Set store_cell = Worksheets(2).Cells(i, m_store.Column)
        Set type_cell = Worksheets(2).Cells(i, m_type.Column)
        Set credit_cell = Worksheets(2).Cells(i, Credit_Amt_Col.Column)

        If InStr(UCase(store_cell.Value), UCase(Store)) > 0 And credit_cell.Value = amount Then
            If store_cell.Interior.ColorIndex <> 46 Then
                If Amex And InStr(UCase(type_cell.Value), UCase("amex deposit")) Then
                    store_cell.Interior.ColorIndex = 46
                    search_bank = True

                End If
                If Not Amex And InStr(UCase(type_cell.Value), UCase("Credit Card Deposit")) Then
                    store_cell.Interior.ColorIndex = 46
                    search_bank = True

                End If
            End If
        End If
    End If
Next i

End Function

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

person Brandon Barney    schedule 16.03.2017
comment
было бы проще Set объектной переменной, а затем просто проверить If Set m_store Is Nothing и т. д. Также меньше накладных расходов и меньше жестко закодированных строковых литералов. - person David Zemens; 16.03.2017
comment
Если вы попытались использовать not after set, вы могли столкнуться с ошибкой «Переменная объекта не установлена», если find не возвращает объект. Это цель инверсионного блока в первую очередь. Кроме того, в идеале я бы исключил жестко запрограммированные строковые литералы и, по возможности, использовал бы объект списка вместо использования Find, но это не Codereview. Можно многое сделать для улучшения кода, но сначала нужно определить проблему. - person Brandon Barney; 16.03.2017
comment
Если переменные введены правильно, If m_store Is Nothing не вызовет никаких ошибок. - person David Zemens; 16.03.2017
comment
Неважно, я проверил это и теперь вижу, что вы имеете в виду. Я почему-то думал, что если Find ничего не найдет, то вы столкнетесь с ошибкой при установке объекта в ничего. Я не знаю, почему я думал, что это так, потому что логика имеет смысл. Думаю, я думал об этом в смысле попытки воздействовать на переменную. В любом случае я отредактирую код, чтобы отразить это. Действительно лучше попробовать установить все три, а затем протестировать все три, чтобы увидеть, содержат ли они что-то. - person Brandon Barney; 16.03.2017
comment
Без проблем! Да, он определенно вызовет Object Required, если вы попытаетесь вызвать любой object.method(), но вы всегда можете безопасно проверить переменную Object на Nothingness. Ваше здоровье! - person David Zemens; 16.03.2017