2017-07-25 86 views
4

我正在编写一些代码来将多个工作表(它们构成各个零件清单)合并为一个大型零件清单。从VBA中排除1行复制范围

到目前为止,我有2个功能,其扫描每个工作表的最后行和列

Function LastRow(sh As Worksheet) 
On Error Resume Next 
LastRow = sh.Cells.Find(What:="*", _ 
         After:=sh.Range("A1"), _ 
         Lookat:=xlPart, _ 
         LookIn:=xlFormulas, _ 
         SearchOrder:=xlByRows, _ 
         SearchDirection:=xlPrevious, _ 
         MatchCase:=False).Row 
    On Error GoTo 0 
End Function 

Function LastCol(sh As Worksheet) 
On Error Resume Next 
LastCol = sh.Cells.Find(What:="*", _ 
         After:=sh.Range("A1"), _ 
         Lookat:=xlPart, _ 
         LookIn:=xlFormulas, _ 
         SearchOrder:=xlByColumns, _ 
         SearchDirection:=xlPrevious, _ 
         MatchCase:=False).Column 
    On Error GoTo 0 
End Function 

然后我有它创建了一个名为“零件清单”新的工作表另一个子并在那里粘贴范围。

Sub CopyRangeFromMultiWorksheets() 
Dim sh As Worksheet 
Dim DestSh As Worksheet 
Dim Last As Long 
Dim CopyRng As Range 

With Application 
    .ScreenUpdating = False 
    .EnableEvents = False 
End With 

' Delete the summary sheet if it exists. 
Application.DisplayAlerts = False 
On Error Resume Next 
ActiveWorkbook.Worksheets("Parts List").Delete 
On Error GoTo 0 
Application.DisplayAlerts = True 

' Add a new summary worksheet. 
Set DestSh = ActiveWorkbook.Worksheets.Add 
DestSh.Name = "Parts List" 


' Loop through all worksheets and copy the data to the 
' summary worksheet. 
For Each sh In ActiveWorkbook.Worksheets 
    If sh.Name <> DestSh.Name Then 

     ' Find the last row with data on the summary worksheet. 
     Last = LastRow(DestSh) 

     ' Specify the range to place the data. 
     ' Set CopyRng = sh.Range("B3:G10"). 
     Set CopyRng = sh.UsedRange 

     ' Test to see whether there are enough rows in the summary 
     ' worksheet to copy all the data. 
     If Last + CopyRng.Rows.Count > DestSh.Rows.Count Then 
      MsgBox "There are not enough rows in the " & _ 
       "summary worksheet to place the data." 
      GoTo ExitTheSub 
     End If 

     ' This statement copies values and formats from each 
     ' worksheet. 
     CopyRng.Copy 
     With DestSh.Cells(Last + 1, "A") 
      .PasteSpecial xlPasteValues 
      .PasteSpecial xlPasteFormats 
      Application.CutCopyMode = False 
     End With 

     ' Optional: This statement will copy the sheet 
     ' name in the H column. 
     DestSh.Cells(Last + 1, "I").Resize(CopyRng.Rows.Count).Value = sh.Name 

    End If 
Next 

ExitTheSub: 

Application.Goto DestSh.Cells(1) 

' AutoFit the column width in the summary sheet. 
DestSh.Columns.AutoFit 

With Application 
    .ScreenUpdating = True 
    .EnableEvents = True 
End With 
End Sub 

我遇到的问题是使用范围复制标题行。有谁知道如何从行和列扫描中排除标题或被复制?

enter image description here enter image description here

感谢所有帮助 丹

+0

标题行固定在位置上,还是它们在单元格类型上有所不同?文本与数字例如?如果你分享你的工作表的样子,这将是有帮助的。 – Luuklag

+0

我已经添加了部件列表的图片(我想删除突出显示为橙色的行)以及每个工作表的外观如何的示例 –

+0

问题与您的复制方式有关。您可以选择工作表中的所有内容并一次全部复制。 Robin Mackenzie的代码将删除第一行,但这在您的示例中不够用。我个人会遍历所有行,并检查单元格A行中的值是否为数字。如果数字则复制,否则下一行。然而,这可能会非常消耗CPU使用量。因此,您必须使用我描述的循环机制以不同的方式定义范围。 – Luuklag

回答

3

没有测试过,但这些方针的东西应该帮助你循环遍历单元格中的所有行,并使用联合函数创建一个新的范围。然后,当检查所有行的数值时,可以使用您的代码复制总范围。

Dim row as integer 
Dim temprange as range 
Dim totalrange as range 
Dim startrow as integer 
For row = 2 to lastrow+1 `assuming there is always a title in row 1 
If IsNum(Cells(row,1)) = false Then 
    If temprange = Nothing then 
     Set temprange = Range(Cells(2,1),Cells(row-1,[lastcolumn number] `[replace with number of last column] 
     startrow = row+1 
    Else 
     Set temprange = Range(Cells(startrow,1),Cells(row-1,[lastcolumn number]) 
    End if 
    If totalrange <> Nothing then 
      Set totalrange = Union(totalrange,temprange) 
    Else 
      Set totalrange = temprange 
    End if 
End if 
Next row 

第二种方法,复制

For row = lastrow to 1 step -1 
If IsNum(Cells(row,1) = False then 
    Rows(row).EntireRow.Delete 
End if 
Next row 

然后再次打电话给你的最后一排功能,做你的代码的其余部分之前删除标题行。

+0

刚想到它,另一种方法是检查数字行,并删除那些没有的行。假设你不需要保存这些行。 – Luuklag

+0

感谢您的想法。第一个答案奏效了,但是,正如你所说的那样,真的会拉上CPU。 我想在第二种方法给你之前,但我不明白我会把它放在我的代码中? –

+0

我认为最好的地方就在之前:CopyRng.Copy – Luuklag

2

如果你有1行,你可以使用下面的函数标题行。如果您有更多的再增加lngTitleRows参数:

Option Explicit 

Sub Test() 

    UsedRangeLessFirstRow(Sheet1, 1).Select 

End Sub 

Function UsedRangeLessFirstRow(ws As Worksheet, lngTitleRows As Long) As Range 

    Dim rngData As Range 
    Dim lngDataRows As Long 
    Dim lngDataColumns As Long 

    Set rngData = ws.UsedRange 
    lngDataRows = rngData.Rows.Count - lngTitleRows 
    lngDataColumns = rngData.Columns.Count 
    Set rngData = rngData.Offset(1, 0).Resize(lngDataRows, lngDataColumns) 

    Set UsedRangeLessFirstRow = rngData 

End Function 

然后,而不是:

Set CopyRng = sh.UsedRange 

用途:

Set CopyRng = UsedRangeLessFirstRow(sh, 1) 
+0

谢谢你的回答,但它似乎并没有为我工作。我相信这是因为@Luuklag给了'你选择了表格中的所有内容并且一次全部复制。 Robin Mackenzie的代码将删除第一行,但这不足以满足您的例子。“ –

+0

再次检查代码。它将删除您复制的每个工作表使用范围的标题行。像我在答案底部提到的那样调用循环中的函数。 HTH –

+0

谢谢!得到它的工作! –

2

如果您有现有的Range,你只是想同Range没有标题行,做一个简单的Intersect-Offset

Set CopyRng = Intersect(CopyRng, CopyRng.Offset(1)) 

这只是需要你给出Range,转移下来一排,然后只保留与原始Range相交的部分。

随着新的Range,你可以安全地做你的CopyRng.Copy,它会排除标题行。

+0

拜伦,的确是一个简单的解决方案。然而,OP的代码显示他一次复制整个工作表,并且工作表包含多个不可预知的距离的标题行。然后循环这一切将是我开始考虑的唯一解决方案。 – Luuklag

+0

@Luuklag,根据第一张照片,我认为这是不正确的。多个标题是将每个工作表复制到一个标题的结果。您可以看到第二张图片是基于代码的输出图纸(粘贴目标)。上面的方法会阻止复制标题,以便输出保持干净。代码需要第一张纸的标志,否则单行Offset-Intersect是排除标题的标准方法。 –

+0

啊我现在看到,我把这两个截图混合起来。然后,你的方法,就像罗宾的方法一样,确实更适合 – Luuklag