在Excel表格中添加新行(VBA)

22

我有一个用于记录每日饮食摄入的Excel表格。在表格中,每一行代表你吃的一种食物及其所含糖分等信息。

然后我添加了一个保存按钮,将所有数据保存到另一个工作表中的表格中。

这是我尝试过的方法。

    Public Sub addDataToTable(ByVal strTableName As String, ByRef arrData As Variant)
    Dim lLastRow As Long
    Dim iHeader As Integer
    Dim iCount As Integer

    With Worksheets(4).ListObjects(strTableName)
        'find the last row of the list
        lLastRow = Worksheets(4).ListObjects(strTableName).ListRows.Count

        'shift from an extra row if list has header
        If .Sort.Header = xlYes Then
            iHeader = 1
        Else
            iHeader = 0
        End If
    End With

    'Cycle the array to add each value
    For iCount = LBound(arrData) To UBound(arrData)
        **Worksheets(4).Cells(lLastRow + 1, iCount).Value = arrData(iCount)**
    Next iCount
End Sub

但是在高亮显示的行出现了相同的错误:

Application-defined or object-defined error

我做错了什么?

先感谢您!

8个回答

33

你没有说明你使用的是哪个版本的Excel。这篇文章是针对2007/2010版的(针对Excel 2003需要采用不同的方法)。

你也没有说明你是如何调用addDataToTable函数以及你传递给arrData参数的内容。
我猜测你正在传递一个基于0的数组。如果是这种情况(且数据表从列A开始),那么iCount将从0计数,而.Cells(lLastRow + 1, iCount)将尝试引用无效的列0

你也没有充分利用ListObject。你的代码假设ListObject1位于第1行开始。如果不是这样,你的代码会把数据放在错误的行中。

下面是一种利用ListObject的替代方案。

Sub MyAdd(ByVal strTableName As String, ByRef arrData As Variant)
    Dim Tbl As ListObject
    Dim NewRow As ListRow

    ' Based on OP 
    ' Set Tbl = Worksheets(4).ListObjects(strTableName)
    ' Or better, get list on any sheet in workbook
    Set Tbl = Range(strTableName).ListObject
    Set NewRow = Tbl.ListRows.Add(AlwaysInsert:=True)

    ' Handle Arrays and Ranges
    If TypeName(arrData) = "Range" Then
        NewRow.Range = arrData.Value
    Else
        NewRow.Range = arrData
    End If
End Sub

可以以多种方式调用:

Sub zx()
    ' Pass a variant array copied from a range
    MyAdd "MyTable", [G1:J1].Value
    ' Pass a range
    MyAdd "MyTable", [G1:J1]
    ' Pass an array
    MyAdd "MyTable", Array(1, 2, 3, 4)
End Sub

我忘了,这是针对Office 2010的。但是这解决了我的问题,谢谢 :) - Miguel Teixeira
在myAdd中设置tbl时,引用特定工作表可能有些限制。或者可以使用以下代码:Set Tbl=range(strTableName).ListObject,这样无论表格在哪里都可以正常工作。 - RowanC
@RowanC 的代码是基于原始代码的,但是你的建议更好。 - chris neilsen
1
██ 速度慢 ██ 使用ListRows.Add非常慢!在一个复杂的工作表中,以这种方式添加100行需要不可接受的35秒!(我已经关闭了事件和屏幕更新)。必须有更好的解决方案。 - Jonas_Hess
3
@Jonas_Hess 我刚刚在一个简单的表格上进行了测试,添加100行只需要<0.5秒。所以不是AddRows慢,而是你的“复杂”表格。你试过在代码运行时将计算设置为手动吗? - chris neilsen
如果您的目标表具有过滤或隐藏列,请小心。我在Excel 2007中使用此宏时遇到了一些奇怪的结果。(例如,某些行被成功添加,但其他行将数组的前半部分复制两次到隐藏列之前和之后)。 - TwiceB

4

Tbl.ListRows.Add对我不起作用,我相信很多人都面临同样的问题。我使用以下方法来解决:

    'First check if the last row is empty; if not, add a row
    If table.ListRows.count > 0 Then
        Set lastRow = table.ListRows(table.ListRows.count).Range
        For col = 1 To lastRow.Columns.count
            If Trim(CStr(lastRow.Cells(1, col).Value)) <> "" Then
                lastRow.Cells(1, col).EntireRow.Insert
                'Cut last row and paste to second last
                lastRow.Cut Destination:=table.ListRows(table.ListRows.count - 1).Range
                Exit For
            End If
        Next col
    End If

    'Populate last row with the form data
    Set lastRow = table.ListRows(table.ListRows.count).Range
    Range("E7:E10").Copy
    lastRow.PasteSpecial Transpose:=True
    Range("E7").Select
    Application.CutCopyMode = False

希望这能对某些人有所帮助。

非常感谢,这对我的情况有所帮助 :) - Mentos

3

我曾经遇到过同样的错误信息,经过多次尝试和错误找出了原因:这是由于在ListObject上设置了高级筛选器导致的。 清除高级筛选后,.listrows.add就可以正常工作了。 为了清除筛选器,我使用以下代码-不知道如何仅清除特定列表对象的筛选器而不是整个工作表。

Worksheets("mysheet").ShowAllData

1
Worksheets("mysheet").ListObjects("tableName").AutoFilter.ShowAllData - HackSlash

1
我刚刚发现,如果您想在表格中选择下面添加多行,Selection.ListObject.ListRows.Add AlwaysInsert:=True非常有效。我只是将代码复制了五次以向我的表格添加五行。

1
我以前也遇到过同样的问题,通过在新工作表中创建相同的表格并删除与表格关联的所有名称范围来解决了它。我相信当您使用listobjects时,不允许在表格中包含名称范围。希望这可以帮助您,谢谢。

0
今天遇到了这个问题(使用.ListRows.Add添加行时Excel崩溃)。 阅读了这篇文章并检查了我的表格后,我意识到某些单元格中的公式计算依赖于其他单元格中的值,甚至是在更高列的单元格和带有公式的偶数单元格!
解决方法是从后往前填充新添加的行,这样计算就不会出错。
Excel通常可以处理不同单元格中的公式,但似乎在表格中添加行会按列(A、B、C等)顺序触发重新计算。
希望这能帮助解决使用.ListRows.Add时的问题。

-1

由于使用ListRow.Add可能会成为一个巨大的瓶颈,因此我们应该只在无法避免时使用它。 如果性能对您很重要,请使用此函数来调整表格大小,这比推荐的添加行方法要快得多。

请注意,如果下面有任何数据,这将覆盖数据

此功能基于Chris Neilsen的被接受的答案。

Public Sub AddRowToTable(ByRef tableName As String, ByRef data As Variant)
    Dim tableLO As ListObject
    Dim tableRange As Range
    Dim newRow As Range

    Set tableLO = Range(tableName).ListObject
    tableLO.AutoFilter.ShowAllData

    If (tableLO.ListRows.Count = 0) Then
        Set newRow = tableLO.ListRows.Add(AlwaysInsert:=True).Range
    Else
        Set tableRange = tableLO.Range
        tableLO.Resize tableRange.Resize(tableRange.Rows.Count + 1, tableRange.Columns.Count)
        Set newRow = tableLO.ListRows(tableLO.ListRows.Count).Range
    End If

    If TypeName(data) = "Range" Then
        newRow = data.Value
    Else
        newRow = data
    End If
End Sub

1
有趣的是,表格中的行数越多,运行速度就越慢。但是当行数达到一定程度时,使用“ListRows.Add”会更快。 - chris neilsen

-2

只需删除表格并使用不同的名称创建新表格。同时,不要删除该表格的整行。似乎当删除包含表格行的整行时,会损坏DataBodyRange。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接