【问题标题】:VBA: Function gives "Run time error '424': Object required" Error when calledVBA:函数在调用时给出“运行时错误'424':需要对象”错误
【发布时间】:2017-03-16 17:54:12
【问题描述】:

我有两个主要功能,第一个是search_bank。它逐个单元格地搜索 Credits、Type 和存储列,并确定我们是否匹配。如果匹配,它返回 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

【问题讨论】:

  • 当您收到运行时错误时,选择“调试”选项并使用 F8 单步执行代码,直到您看到错误所在的行。
  • 您在何处/何时/如何声明bank_sheet
  • 另外,确保您的三个Find 方法的结果返回有效对象。如果在第 1 行中找不到这些值,则它们将返回 Nothing,这将在您的代码中稍后引发此错误。
  • Range.Find 可以返回Nothing。您必须测试返回值。
  • @RyanFrancis FWIW 你确实有一个免费的全局工作表对象。查看 Project Explorer 工具窗口;工作表节点显示为Sheet1 (Sheet1) - 那是CodeName (WorksheetName),其中CodeName 是您免费获得的全局范围Worksheet 对象变量。您可以在 properties 工具窗口 (F4) 中通过更改 (Name) 属性来控制其名称。

标签: vba excel basic


【解决方案1】:

如果可以的话,我会将此作为评论发布,但我不能。所以我知道这不会直接解决它,但它有助于调试。见下文:

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

我在内联发布了一条评论,但基本上我为您的前三个对象添加了一个反向检查(您也希望为您的第二组对象执行此操作)。这是最佳做法,但在这种情况下,它也(希望)帮助您查明找不到对象的位置。

【讨论】:

  • 会更容易Set 对象变量,然后简单地测试If Set m_store Is Nothing 等。也更少的开销,更少的“硬编码”字符串文字。
  • 如果您尝试在 set 后使用 not,如果 find 没有返回对象,您可能会遇到“未设置对象变量”错误。这首先是反转块的意图。此外,理想情况下,我会消除硬编码的字符串文字,如果可能的话,可能会使用 listobject 而不是使用 Find,但这不是 Codereview。可以做很多事情来改进代码,但必须首先确定问题。
  • 如果变量输入正确,If m_store Is Nothing 不会引发任何错误。
  • 没关系,我测试了它,看看你现在的意思。出于某种原因,我认为如果 Find 什么也没找到,那么在将对象设置为空时会遇到错误。我不知道为什么我认为是这种情况,因为逻辑是有道理的。我想我是在试图对变量采取行动的意义上考虑它。无论如何,我将编辑代码以反映这一点。确实最好尝试设置所有三个,然后测试所有三个以查看它们是否包含某些内容。
  • 别担心!是的,如果您尝试调用任何 object.method(),它将定义一个 Object Required,但您始终可以安全地测试 Nothingness 的 Object 变量。干杯!
【解决方案2】:

在您的 OP 下有很多很好的评论,@BrandonBarney 的回答也是如此,但这是我的两分钱:

一分钱:我看到的最大的事情是你从来没有声明 blank_sheet 却尝试在设置范围对象时使用它。这就是您的错误的来源。它正在寻找Range("1:1").Find("M_STORE"),但不知道bank_sheet 是什么。

美分二:向您指出这一点的一种快速方法是在代码顶部发送always use Option Explicit。这可确保您使用的 any 变量被显式声明。即:

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_storem_type 成为 Variant,因为它没有被声明。只有 Credit_Amt_Col 会在这种情况下是Range。所以你仍然必须明确声明每个变量的类型)。

【讨论】:

    猜你喜欢
    • 2013-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-01
    相关资源
    最近更新 更多