You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Excel VBA宏复制功能异常行为排查与解决方案咨询

VBA宏复制范围异常问题

编辑补充:触发问题的条件似乎是当LastRowNo等于常量StartRowNo(值为3)时,宏会将单元格复制到自身。我在复制函数前添加了If LastRowNo = StartRowNo Then Exit Sub语句,问题暂时解决,但这只是临时 workaround,因为理论上单元格复制到自身不应引发问题,特此保留问题以寻求根源解析。

我编写的VBA宏最初运行正常,但偶尔会出现异常:将单元格A3的内容复制到整个工作表的第1至25列,范围直至LastRowNo变量获取的最后一行。

引发问题的代码行如下:

.Range(StartRow).Copy _
    Destination:=.Range(StartRow & ":A" & LastRowNo).SpecialCells(xlCellTypeBlanks)

若注释该行代码,下方的复选框复制代码会出现同样的异常,将复选框复制至相同范围:

For ColumnNo = 16 To 25
      Escopo.Cells(StartRowNo, ColumnNo).Copy _
         Destination:=.Range(Escopo.Cells(StartRowNo, ColumnNo), Escopo.Cells(LastRowNo, ColumnNo)).SpecialCells(xlCellTypeBlanks)
Next

更奇怪的是,假设某次错误发生时LastRowNo的值为20,删除所有数据后将LastRowNo设置为4,宏仍会复制到第20行,只有当LastRowNo设为大于20的值时,范围才会更新。仿佛宏在End Sub后仍留存该值,仅会被更大的值覆盖。

我无法稳定复现该错误,其出现无明显规律。


完整代码

FormatWB 主过程

Sub FormatWB()
    
    Dim StartRow As String
    Dim LastRowNo As Long
    Dim ColumnNo As Long
    Dim Escopo As Worksheet
    Dim Material As Worksheet
    Dim PrecoMTL As Worksheet
    Dim PrecoRev As Worksheet
    Dim Orcamento As Worksheet
    Const StartRowNo = 3
    
    Set Escopo = ActiveWorkbook.Worksheets("Escopo")
    Set Material = ActiveWorkbook.Worksheets("Material")
    Set PrecoMTL = ActiveWorkbook.Worksheets("Preço Material")
    Set PrecoRev = ActiveWorkbook.Worksheets("Preço Revestimento")
    Set Orcamento = ActiveWorkbook.Worksheets("Orçamento Final")
    
    Application.DisplayAlerts = False
    Application.ScreenUpdating = False
    
        With Escopo '根据非空单元格数量计算限制范围
            LastRowNo = .Cells(.Rows.Count, "B").End(xlUp).Row '该值会在RemoveSumDuplicates过程中更新
                If LastRowNo < StartRowNo Then Exit Sub
            StartRow = "A" & StartRowNo
                Call RemoveSumDuplicates(StartRowNo, LastRowNo, StartRow)
        End With
        
        With ActiveWorkbook '统一格式化所有工作表,范围到指定最后一列
            FormatSheet Escopo.Range(StartRow & ":Y" & LastRowNo)
            FormatSheet Material.Range(StartRow & ":N" & LastRowNo)
            FormatSheet PrecoMTL.Range(StartRow & ":P" & LastRowNo)
            FormatSheet PrecoRev.Range(StartRow & ":O" & LastRowNo)
            FormatSheet Orcamento.Range(StartRow & ":Q" & LastRowNo)
        End With
        
        With Escopo
            On Error Resume Next
                .Range("A3").Formula = "=IF(ISBLANK(B3),"""",IFERROR(A2+1,1))"
                .Range(StartRow & ":A" & LastRowNo).Font.Bold = True
                .Range("P3:R3").CellControl.SetCheckbox
                .Range("S3").FormulaArray = "=INDEX('Database QPs e IPs'!$H$2:$H$150,MATCH(1,(Escopo!$K3='Database QPs e IPs'!$A$2:$A$150)*(Escopo!$L3='Database QPs e IPs'!$B$2:$B$150),0))"
                .Range("T3").FormulaArray = "=INDEX('Database QPs e IPs'!$G$2:$G$150,MATCH(1,(Escopo!$K3='Database QPs e IPs'!$A$2:$A$150)*(Escopo!$L3='Database QPs e IPs'!$B$2:$B$150),0))"
                .Range("U3").FormulaArray = "=INDEX('Database QPs e IPs'!$I$2:$I$150,MATCH(1,(Escopo!$K3='Database QPs e IPs'!$A$2:$A$150)*(Escopo!$L3='Database QPs e IPs'!$B$2:$B$150),0))"
                .Range("V3").FormulaArray = "=INDEX('Database QPs e IPs'!$N$2:$N$150,MATCH(1,(Escopo!$K3='Database QPs e IPs'!$A$2:$A$150)*(Escopo!$L3='Database QPs e IPs'!$B$2:$B$150),0))"
                .Range("W3").FormulaArray = "=INDEX('Database QPs e IPs'!$K$2:$K$150,MATCH(1,(Escopo!$K3='Database QPs e IPs'!$A$2:$A$150)*(Escopo!$L3='Database QPs e IPs'!$B$2:$B$150),0))"
                .Range("X3").FormulaArray = "=INDEX('Database QPs e IPs'!$J$2:$J$150,MATCH(1,(Escopo!$K3='Database QPs e IPs'!$A$2:$A$150)*(Escopo!$L3='Database QPs e IPs'!$B$2:$B$150),0))"
                .Range("Y3").FormulaArray = "=INDEX('Database QPs e IPs'!$O$2:$O$150,MATCH(1,(Escopo!$K3='Database QPs e IPs'!$A$2:$A$150)*(Escopo!$L3='Database QPs e IPs'!$B$2:$B$150),0))"
                .Range(StartRow).Copy _
                    Destination:=.Range(StartRow & ":A" & LastRowNo).SpecialCells(xlCellTypeBlanks)
                For ColumnNo = 16 To 25
                    Escopo.Cells(StartRowNo, ColumnNo).Copy _
                        Destination:=.Range(Escopo.Cells(StartRowNo, ColumnNo), Escopo.Cells(LastRowNo, ColumnNo)).SpecialCells(xlCellTypeBlanks)
                Next
        End With
        
    Application.ScreenUpdating = True
    Application.DisplayAlerts = True

End Sub

FormatSheet 格式化过程

Sub FormatSheet(rng As Range)
    With rng
        .UnMerge
        .Borders.LineStyle = xlContinuous
        .HorizontalAlignment = xlCenter
        .VerticalAlignment = xlCenter
        .NumberFormat = "General"
        .Font.Bold = False
        .Font.Italic = False
        .Font.Underline = False
        .Font.Name = "Calibri"
        .Font.Size = 11
        .Interior.ColorIndex = 0
        .Font.Color = vbBlack
    End With
End Sub

RemoveSumDuplicates 去重求和过程

Sub RemoveSumDuplicates(StartRowNo As Long, LastRowNo As Long, StartRow As String)
    Dim Value As Object
    Dim RowNo As Long
    Dim Label As String

    Set Value = CreateObject("Scripting.Dictionary")

    For RowNo = StartRowNo To LastRowNo
        Label = Cells(RowNo, 2)
        Value(Label) = Cells(RowNo, 7) + Value(Label)
    Next RowNo
    
    Range(StartRow & ":Y" & LastRowNo).RemoveDuplicates Columns:=Array(2, 2)
    LastRowNo = Cells(Rows.Count, "B").End(xlUp).Row

    For RowNo = StartRowNo To LastRowNo
        Label = Cells(RowNo, 2)
            If Not Cells(RowNo, 7) = Value(Label) Then Cells(RowNo, 7) = Value(Label)
    Next RowNo
End Sub

内容的提问来源于stack exchange,提问作者Bkviegas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 02:54:52