【问题标题】:PasteSpecial twice crashes Excel VBAPasteSpecial 两次崩溃 Excel VBA
【发布时间】:2021-07-21 16:47:50
【问题描述】:

我一直在寻找在 excel vba 宏中多次使用 .PasteSpecial 的解决方案。 我的报告有时可能有数千行。在这些报告中有两列,我需要合并这些列,以便如果一列有空白,我想要第二列的值;否则,只需将值保留在第一列中。我需要在两个不同的地方应用两次。这一切都隐藏在一个更大的代码中。

我的解决方案是使用带有“跳过空白”的 .PasteSpecial。 excel处理速度很快,比逐行循环快得多。问题是代码不断崩溃excel。

调试后,这是我到目前为止所学到的: *第一个 .PasteSpecial 始终有效,但当它到达第二个 .PasteSpecial 时,它总是失败。 *我在第一个 .PasteSpecial 之后尝试了 STOP,然后单步执行代码,在我单步执行第二个.PasteSpecial 之后,代码工作得很好。 *如果我单步执行第二个 .PasteSpecial,它的工作原理就像没有任何问题一样 - 但如果我像正常一样运行代码,它就会崩溃。 *我在代码中切换了两个 .PasteSpecials 的顺序。当我这样做时,它不再在有问题的 .PasteSpecial 上崩溃,但它确实在最初工作的 .PasteSpecial 上崩溃。

基于此,我知道问题是 Excel 不喜欢 .PasteSpecial 在代码中两次。仍然找不到解决方法。我试过清空剪贴板,但我不知道如何设置一个数组,更不用说对这么多数据有效了。有人知道解决方案或解决方法吗?

这是我的 .PasteSpecial 代码:

MainSheet.Range("N:N").Copy
MainSheet.Range("P:P").PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:=True, Transpose:=False

MainSheet.Range("R:R").Copy
MainSheet.Range("Q:Q").PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:=True, Transpose:=False

【问题讨论】:

  • 如果您尝试手动复制 / PasteSpecial 会发生什么?
  • 你有没有试过把Application.CutCopyMode=False放在两个复制/粘贴操作之间?
  • 你也需要复制格式吗?
  • 如果我尝试手动操作它就可以了。我试过 Application.CutCopyMode=False ,它仍然崩溃。我也不需要格式化。

标签: excel vba crash copy copy-paste


【解决方案1】:

您的问题是当您实际上不需要粘贴任何内容时,您正在提交 CPU 来执行操作系统级别的任务。

单元格具有值...所以使它们相等,它们...将...成为...

Range("C1").Value = Range("A1").Value

或者,您可以使用电源查询来执行此操作,其中表 2 Col2 为空且 ID = ID

【讨论】:

  • 嗨,谢谢你的回答,但这并不能实现我的目标。详细说明我的目标:我使用 .PasteSpecial 的原因是“跳过空白”,这样如果第一列中有任何空白,并且第二列(同一行)中有文本,它就不会删除第二列的文本。但是,如果两者都有文本,则第一列的文本会覆盖第二列的文本。
【解决方案2】:

不需要格式,请测试下一段代码。它使用数组,不使用剪贴板并且速度更快。如果两个填充列中的行之间不需要存在对应关系,则可以使用下一个快速方法:

Sub copyColumnsArray()
 Dim lastR As Long, arrCopy, arrFin, i As Long, k As Long
 
 lastR = MainSheet.Range("N" & rows.count).End(xlUp).row
 arr = MainSheet.Range("N1:N" & lastR).value
 
 'fill another array only with non empty values:__________________
 ReDim arrFin(UBound(arr) To 1): k = 1
 For i = 1 To UBound(arrCopy)
    If arrCopy(i, 1) <> "" Then arrFin(k, 1) = arrCopy(i, 1): k = k + 1
 Next i
 ReDim Preserve arrFin(k - 1 To 1)
 '______________________________________________________
 
 MainSheet.Range("P1").Resize(UBound(arrFin), 1).value = arrFin
 
 lastR = MainSheet.Range("R" & rows.count).End(xlUp).row
 arr = MainSheet.Range("R1:R" & lastR).value
 
 'fill another array only with non empty values:__________________
 ReDim arrFin(UBound(arr) To 1): k = 1
 For i = 1 To UBound(arrCopy)
    If arrCopy(i, 1) <> "" Then arrFin(k, 1) = arrCopy(i, 1): k = k + 1
 Next i
 ReDim Preserve arrFin(k - 1 To 1)
 '______________________________________________________
 
 MainSheet.Range("Q1").Resize(UBound(arrFin), 1).value = arrFin
End Sub

【讨论】:

  • 嗨,谢谢你的回答,但它不起作用。让代码运行后,它将第一列的空白填充到第二列。详细说明我的目标:我使用 .PasteSpecial 的原因是“跳过空白”,这样如果第一列中有任何空白,并且第二列(同一行)中有文本,它就不会删除第二列的文本。但是,如果两者都有文本,则第一列的文本会覆盖第二列的文本。
  • @Steven 请尝试更新的代码。我使用(错误地)arr,甚至没有声明,而不是arrCopy。我最初使用arr 测试了代码,然后我认为使用arrCopy 会更加elocvent... 在连续步骤中使用SkipBlanks,如果同一行上不存在空单元格可能会产生问题...
  • 我确实注意到 arr 和 arrCopy 断开连接 - 我想这可能就是您的意思,所以不用担心。我认为使用数组方法的问题在于,当它构建数组时,它会在相应的索引中放置一个“”,因此当它更改第二列的值时,它每次都放置“”而不是跳过空白。我正在尝试使用诸如“如果值 if arrCopy = ”然后“跳过其他...”之类的想法,您能否帮助代码使其跳过输入数组值(如果它是空白)?
  • 我找到了解决方案并将其输入到您的帖子中,以便将其标记为正确答案。编辑获得批准后,我会将其标记为正确答案。感谢您的帮助!
  • @Steven 如果有必要跳过空单元格,我会调整代码,但不像你尝试过的那样。当您将值粘贴到单元格时,会消耗最多的时间和资源。如果两列行之间的相关性无关紧要,我将创建第二个数组以仅接收非空单元格并立即删除其内容
【解决方案3】:

编辑:

下面是一个比我最初找到的解决方案更可靠的更好答案。这是对 FaneDuru 回答中的一些建议的改编。这种解决方案对资源的负担更大;但是,就目前而言 - 它可靠地执行任务(不会崩溃)。我希望有比行循环更好的答案;但是,这确实回答了我的 OP。谢谢大家的帮助!

    Sub copyColumnsArray()
 Dim lastR As Long, arrCopy
 
 lastR = MainSheet.Range("N" & rows.count).End(xlUp).row
 arrCopy = MainSheet.Range("N1:N" & lastR).value 

Dim ArrayIndex as Variant
Dim RowCount as String
RowCount = 1

For Each ArrayIndex in arrCopy
  If ArrayIndex = "" then
    RowCount = RowCount +1
    'Skip Blank
   else
    MainSheet.Range("P"+RowCount).value = ArrayIndex
    RowCount = RowCount + 1
   end if
 Next
 

 lastR = MainSheet.Range("R" & rows.count).End(xlUp).row
 arrCopy = MainSheet.Range("R1:R" & lastR).value

RowCount = 1

For Each ArrayIndex in arrCopy
  If ArrayIndex = "" then
    RowCount = RowCount +1
    'Skip Blank
   else
    MainSheet.Range("Q"+RowCount).value = ArrayIndex
    RowCount = RowCount + 1
   end if
 Next

End Sub

【讨论】:

  • 看来是Excel必备资源的问题,在之前的粘贴过程完成之前就尝试粘贴了。这不是正常行为,VBA 应自行等待,直到操作完成。更好的解决方案应该是使用数组,它根本不涉及剪贴板并且消耗更少的 Excel 资源。我发布了一段代码,可以替换你的,更稳定,更快。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-24
  • 1970-01-01
相关资源
最近更新 更多