Excel VBA函数运行时错误1004:应用程序定义的错误或对象定义的错误


5

我正在尝试学习函数,以便在必要时简化和重用代码。

我开始将经常使用的东西转换成函数:返回电子表格中最后一个非空白列的整数值。

Function FindLastDataLine(strColName As String) As Long
    FindLastDataLine = Range(strColName).Offset(Rows.Count - 1, 0).End(xlUp).Row
End Function

Sub PracticeMacro()
    intItemCount = FindLastDataLine("A:A")
    MsgBox ("There are " & intItemCount & " rows of data in column A.")
End Sub

当我运行它时,我收到运行时错误'1004'“应用程序定义或对象定义的错误”,这有助于帮助定义为“别人的错”,并不是一字不差地引用。

我哪里可能出错?


始终Option Explicit在代码顶部使用,并显式声明变量。我不能说实践作为程序员是多么重要。
突破

谢谢@Breakthrough。自这条评论以来的几年里,我已经养成了这样做的习惯。
music2myear 2016年

Answers:


4

为什么你的方法不起作用:这里有两个原因。第一个,当你放Rows.Count,没有参考Rows- 它是一个属性Range。要修复它,你只需要引用你已经存在的相同范围(只需在你调用之前附加它Rows.Count

Function FindLastDataLine(strColName As String) As Long
    FindLastDataLine = Range(strColName).Offset(Range(strColName).Rows.Count - 1, 0).End(xlUp).Row
End Function

第二个原因是你正在使用OffsetOffset字面意思是Range根据你说的多少来改变。您不希望移动整个范围的单元格,而是查找范围中的最后一个单元格。您可以通过更改OffsetCells删除初始Range()调用(因为我们将选择一个单元格)并更改0为您想要的列来完成此操作。但是,因为您将列传递为"A:A",这是不可能的,所以您必须使用Range(strColName).Column以下内容替换它:

Function FindLastDataLine(strColName As String) As Long
    FindLastDataLine = Cells(Range(strColName).Rows.Count, Range(strColName).Column).End(xlUp).Row
End Function

更好的解决方案:以下解决方案适用于所有最新版本的MS Office(2003,2007和2010),并将处理错误。您可以通过传递列字母或列号来调用它:

Function GetLastDataRow(col As Variant) As Long
    GetLastDataRow = -1
    If (IsNumeric(col) And col >= 1) Or Len(col) <= 2 Then
        On Error Resume Next
        GetLastDataRow = _
            Cells(Cells(1, col).EntireColumn.Rows.Count, col).End(xlUp).Row
        On Error GoTo 0
    End If
End Function

以下说明了如何调用此函数以及一些示例输出。让我们假设整个页面清晰,除了在单元格中输入一些随机数据B1,以B8B10B9留空)。请注意,不要将列作为范围输入,而是输入列字母列号(无效值返回-1):

GetLastDataRow(1)         =  1    GetLastDataRow("A")       =  1
GetLastDataRow(2)         = 10    GetLastDataRow("B")       = 10
GetLastDataRow("AX")      =  1    GetLastDataRow("A:X")     = -1
GetLastDataRow("Oops...") = -1    GetLastDataRow(200)       =  1

作为技术说明,如果Cells方法失败,则假定输入无效,因此函数返回-1。我建议你在函数中使用这种做法(如果输入无效则返回无效值),它将极大地帮助你避免将来出现错误。

如何工作,它找到任何特定列中的最后一行(取决于您的MS Office版本),然后使用该End方法查找该列中包含数据的最后一个单元格。


这是一个替代版本,如果该列中的所有单元格都为空,则返回0:

Function GetLastDataRow(col As Variant) As Long
    GetLastDataRow = -1
    If (IsNumeric(col) And col >= 1) Or Len(col) <= 2 Then
        On Error Resume Next
        If IsEmpty(Cells(Cells(1, col).EntireColumn.Rows.Count, col).End(xlUp).Value) Then
            GetLastDataRow = 0
        Else
            GetLastDataRow = _
                Cells(Cells(1, col).EntireColumn.Rows.Count, col).End(xlUp).Row
        End If
        On Error GoTo 0
    End If
End Function

示例输出:

GetLastDataRow(1)         =  0    GetLastDataRow("A")       =  0
GetLastDataRow(2)         = 10    GetLastDataRow("B")       = 10
GetLastDataRow("AX")      =  0    GetLastDataRow("A:X")     = -1
GetLastDataRow("Oops...") = -1    GetLastDataRow(200)       =  0

好吧,对不起,我们花了很长时间才重新开始这个,但是这里有。一个问题:参考你的答案的第一部分,如果我通过了FindLastDataLine(“A:1”),当前的系统会工作,因为它指定了一个Row可以工作而不是范围的单元格?这只是侧重于第一部分,以便我可以更好地理解您的建议。
music2myear 2011年

对不起,我不太明白你的问题...... "A:1"本身并不是一个有效的范围。我写的自定义功能之前,你需要传递的有效范围为字符串(即A:AA2:A15等...)。
突破

好。我懂了。感谢您对问题和解决方案的详尽描述。
music2myear 2011年

1

您写了“返回电子表格中最后一个非空白行的整数值”。但看起来您正试图在电子表格的特定列中获取最后一个非空白行。

如果你改变你的功能,我认为它会起作用:

Function FindLastDataLine(strColName As String) As Long
    FindLastDataLine = ActiveSheet.Cells(ActiveSheet.Rows.Count, strColName).End(xlUp).Row
End Function

1
Yeap ......似乎主题说了一件事,函数命名另一个......而代码本身又是另一回事。
Tiago Cardoso

谢谢,这让我发笑。我认为这个评论可能适用于很多问题。
佩里

对不起,我确实在寻找列中最后一个非黑色单元格的整数值,而不是一行。我的错。
music2myear 2011年

1

它可能无法修复您的错误,但会返回范围内的ItemCount ...

Function FindLastDataLine(strColName As String) As Long
    FindLastDataLine = Evaluate("COUNTA(" & strColName & ")")
End Function

Sub PracticeMacro()
    intItemCount = FindLastDataLine("A:A")
    MsgBox ("There are " & intItemCount & " rows of data in column A.")
End Sub

请注意,还有其他一些方法可以调用此COUNTA Excel函数...


这没有考虑空白列,因此它甚至没有接近原始海报的“返回电子表格中最后一个非空白行的整数值”。
突破

看看消息框说什么...... MsgBox ("There are " & intItemCount & " rows of data in column A.")。AFAIK,COUNTA就是这样做的。看看我对@PerryJ帖子的评论。
Tiago Cardoso

1
对不起,没看到 - 好的电话。要爱在代码中使用可怕的模糊名字的人。
突破

NW。我相信@ music2myear的目标是测试他的技能,而不是做一个特定的开发...所以我猜他有一个'默认'代码他重新调整(但没有更新一些可以帮助我们的东西,喜欢消息框)。
Tiago Cardoso

我正在从事特定的工作。有一个现有的宏可以正确执行任务。但是,它使用了几种效率极低的方法。我的目标是通过重建宏来更有效地执行任务,以及将几个宏前和宏后进程滚动到宏本身。这适用的过程应该从5分钟的任务到30秒的不干涉任务。
music2myear 2011年

0

尝试:

FindLastDataLine = _
     Range(strColName).Offset(ActiveSheet.Rows.Count - 1, 0).End(xlUp).Row

行是一个属性。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.