【问题标题】:Copying an array to a filtered range gives irrational results将数组复制到过滤范围会产生不合理的结果
【发布时间】:2012-04-26 21:28:00
【问题描述】:

将过滤范围的值复制到数组似乎没有问题:然后数组包含来自过滤和未过滤单元格的值。但是,当我将数组的内容复制回过滤范围时,结果对我来说是不可理解的。

这是我的代码:

Sub test()
    Dim rangecopy() As Variant

    rangecopy() = Range(Cells(2, 1), Cells(14, 3)).Value
    For c = LBound(rangecopy, 1) To UBound(rangecopy, 1)
        rangecopy(c, 1) = c
        rangecopy(c, 2) = c * 10
        rangecopy(c, 3) = c * 100
    Next
    Range(Cells(2, 1), Cells(14, 3)).Value = rangecopy()
End Sub

它应该给出以下结果。此处,宏将数组复制到该范围时,该范围未过滤。

如果范围被D列过滤(“NO”被过滤掉),结果如下:

首先,过滤后的单元格不会更新。然后,B 列中的大多数单元格从数组的第一列 (4, 5, 6) 中获取值,而其他一些单元格从数组的第二列 (10) 中正确获取值。最后两行填充了#N/A 错误。这应该这样工作吗?我正在使用 Office 2010。

【问题讨论】:

  • 仅供参考,我得到了相同的结果。还不知道为什么。
  • 您使用的是什么版本的 Excel?
  • 我在 Excel 2003 中使用相同的代码得到相同的结果。如果我用 Set RngUnion = Application.Union(Range("A2:C2"), Range("A4:C6"), Range("A8:C8"), Range("A10:C14"))RngUnion = rangecopy 替换最后一条语句,我也会得到相同的结果。所以原因不是 AutoFilter 而是 Union。
  • 使用Set RngUnion = Application.Union(Range("A2:C2"), Range("A3:C6"), Range("A7:C8"), Range("A9:C14"))(也就是说,联合中没有间隙),我得到了正确的结果。使用Set RngUnion = Application.Union(Range("A2:C2"), Range("A4:C6"), Range("A8:C8"), Range("A10:C14"), Range("A16:C18"))(即联合组成与数组大小相同),前四个子范围与以前一样,但最后一个子范围设置为数组的前三行。跨度>

标签: excel excel-2010 vba


【解决方案1】:

我真的希望了解 VBA 内部工作原理的人可以对您的问题提供更多见解。我可以分享以下内容:

首先,它按预期工作。但是,我不知道为什么会这样设计,也不知道分配过程中到底发生了什么。

有很多情况会产生类似的问题。例如,如果您打开过滤器(某些行被隐藏)并尝试向下填充(拖动)公式,您将看到类似的结果,因为隐藏的行没有被填充,但它们确实会影响(相对)引用在公式。另一方面,如果您手动复制并粘贴到过滤范围中,则数据将粘贴到隐藏行中(如您所愿)。

似乎作为自动过滤器范围一部分的任何引用范围实际上都是不连续的*。使用 Range.Address 并不总能揭示这一点,循环 Range.Areas 也不会。如果我们修改您的示例,我们可以看到“真正的”错误在哪里:

Dim r1 as range
Dim r2 as range

Set r1 = Sheet1.Range("A1:B5") 'some numbers in a range
Set r2 = Sheet2.Range("A2:B6") 'same-size range underneath a filtered header

r1.Copy Destination:=r2

它在所有行都可见时起作用。当 Sheet2 上的过滤器创建隐藏行时,结果是“运行时错误 '1004': ...复制区域和粘贴区域的大小和形状不同。”另一方面,使用“手动”/剪贴板方法适用于隐藏行:

r1.Copy    
r2.PasteSpecial (xlPasteValues)

由于将数组分配给范围会绕过剪贴板(如在第一个块中),我们应该收到一个错误(而不是您最终得到错误的结果)。

我知道的唯一解决方案是循环遍历范围并为每个单元格分配一个值:

For i = 1 to LastRow
  For j = 1 to LastCol
    Sheet1.Cells(i,j).Value = myArr(i,j)
  Next
Next

或(更好)删除自动过滤器,将数组分配给范围,然后重新应用过滤器。

*从技术上讲它是连续的,因此最好说该范围由多个范围/区域组成,尽管使用 .Address 并不表示这一点,并且当您尝试循环遍历 Range.Areas 时只有一个区域

【讨论】:

  • 感谢 Zairja。是否可以保存自动筛选设置以便以后重新应用?或者更好的是,是否可以在不丢失其设置的情况下禁用自动过滤器,然后再重新启用它?
  • 我相信this 应该适合你。还有几件事要补充。从过滤范围复制时要小心。直接复制 (r1.copy dest:= r2) 仅复制可见行。从过滤范围(带有隐藏行)直接复制到另一个过滤范围(带有隐藏行),会引发错误 1004:“该命令不能用于多项选择。”因此,似乎自动过滤器(当它创建隐藏行时)将连续范围分解为多个选择。
猜你喜欢
  • 2021-12-28
  • 2021-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-04
  • 1970-01-01
相关资源
最近更新 更多