在VBA复制粘贴过程中导致运行时错误1004的“Application.Calculation = xlCalculationManual”语句

时间:2014-12-20 02:09:16

标签: excel vba excel-vba selection copy-paste

我有VBA代码复制第一行并将值粘贴到多行。下面的代码运行正常并按预期粘贴行:

Sub Macro1()
  Dim i As Long

  Application.Calculation = xlCalculationManual
  Range("A1:M1").Select
  Selection.Copy

  For i = 1 To 50
    Range("A" & i).Select
    Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
      :=False, Transpose:=False
  Next i
End Sub

但是,如果我将Application.Calculation = xlCalculationManual向下移动两行,则代码会抛出1004运行时错误:

Sub Macro1()
  Dim i As Long    

  Range("A1:M1").Select
  Selection.Copy
  Application.Calculation = xlCalculationManual
  For i = 1 To 50
    Range("A" & i).Select
    Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
      :=False, Transpose:=False
  Next i
End Sub

我在此处搜索了有关VBA语言参考站点的信息:http://msdn.microsoft.com/en-us/library/office/jj692818(v=office.15).aspx以及此处的Excel开发人员参考站点:http://msdn.microsoft.com/en-us/library/office/ff194068(v=office.15).aspx

此外,我使用在Windows 7上运行的Excel 2010和在Windows 8.1上运行的2013验证了此错误。

有人可以帮我理解为什么Application.Calculation = xlManualCalculation的位置会影响代码的运行方式吗?

修改

我运行了一些额外的测试来检查焦点是否丢失或剪贴板是否已清除。首先看看焦点是否丢失我录制了一个用ctrl + x复制第一行的宏,然后我改变了工作簿的计算模式,然后再次点击ctrl + x而不重新选择单元格。这是结果宏:

Sub MacroFocusTest()
    Range("A1:M1").Select
    Selection.Copy
    Application.CutCopyMode = False 'Macro recording entered this.
    Application.Calculation = xlManual
    Selection.Cut 'Range("A1:M1") is cut on the worksheet suggesting focus was not lost.
End Sub

接下来,我在原始Macro1中输入了一个变量,以便在执行的各个阶段捕获Application.CutCopyMode。以下是结果宏:

Sub Macro1()
  Dim i As Long
  Dim bCCMode as Boolean    

  bCCMode = Application.CutCopyMode ' False
  Range("A1:M1").Select
  Selection.Copy
  bCCMode = Application.CutCopyMode ' True
  Application.EnableEvents = False ' Included because I mention in comments no error is thrown using this
  bCCMode = Application.CutCopyMode ' True
  Application.Calculation = xlCalculationManual
  bCCMode = Application.CutCopyMode ' False
  For i = 1 To 50
    Range("A" & i).Select
    Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
      :=False, Transpose:=False
  Next i
End Sub  

根据这两个测试的结果,我认为Application.Calculation = xlCalculationManual不会导致范围失去焦点,但会清除剪贴板。

2 个答案:

答案 0 :(得分:2)

您正在更改复制和粘贴之间的焦点。当您这样做时,Excel会丢失复制的数据,在您尝试粘贴时会出现错误。如果您尝试按此顺序从工作表中执行此操作,则会发生同样的情况。

Excel并不像其他程序那样真正使用系统剪贴板。我认为这与在复制数据中更改单元格引用有关的问题有关。

如果您只想粘贴值,可以尝试使用Office剪贴板,但在最新版本的Excel中,我不知道VBA支持。

您可能会发现此感兴趣的回复。它引用了Excel开发人员Prevent Excel from clearing copied data for pasting, after certain operations, without Office clipboard

的注释

答案 1 :(得分:2)

对于您的具体问题,答案是:Application.Calculation = xlCalculationManual语句删除剪贴板内存,这会导致代码段中的后续运行时错误。

注意:还有另一个建议的解释是'Excel副本失去焦点';它可能只是一个语义上的差异,指向相同的效果,只是措辞不同,但为了更清晰,我更喜欢这一个,即剪贴板内存(或任何你称之为临时寄存器)失去价值或参考。

用于证明/说明概念和详细解释的测试设置如下:

'Error occured because a statement
'Application.Calculation = xlCalculationManual
'or Application.Calculation = xlAutomatic
'or Application.Calculation = xlManual
'placed after `Selection.Copy` clears the clipboard memory;
'thus there is nothing to paste and Error 1004 occured
'as demonstrated in the added test code block
Sub YourMacroWithProblem()
    Dim i As Long

    Range("A1:M1").Select

    'Selected Range content is placed to Clipboard memory
    Selection.Copy

    'This statement erases Clipboard memory
    Application.Calculation = xlCalculationManual

    ' test if clipboard is empty ---------------------
    On Error Resume Next
    ActiveSheet.Paste
    If Err Then MsgBox "Clipboard is Empty": Err.Clear
    '-------------------------------------------------

  For i = 1 To 50
    Range("A" & i).Select
    Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
      :=False, Transpose:=False
  Next i
End Sub

此外,还有一个关于类似主题的旧讨论:从清除剪贴板中停止VB (链接:http://www.mrexcel.com/forum/excel-questions/459793-stop-vbulletin-clearing-clipboard-3.html)。

您可以考虑针对速度和可靠性优化的问题采用以下解决方案:

Sub Macro2()
    Dim i As Long

    Application.Calculation = xlCalculationManual
    Application.ScreenUpdating = False

    For i = 1 To 50
        Range("A1:M1").Copy Destination:=Range("A" & i)
    Next i

    Application.Calculation = xlCalculationAutomatic
    Application.ScreenUpdating = True

End Sub

注意:与有问题的代码段不同,在建议的解决方案中不需要Select语句和剪贴板复制/粘贴操作,因此任何潜在的副作用都将被最小化。

希望这可能会有所帮助。亲切的问候,