有没有简单/简短的方法来获取复制工作表时获得的新工作表的Excel.worksheet对象?
ActiveWorkbook.Sheets("Sheet1").Copy after:=someSheet
事实证明,.Copy方法返回布尔值而不是工作表对象。否则,我本可以做到:
set newSheet = ActiveWorkbook.Sheets("Sheet1").Copy after:=someSheet <-- doesn't work
所以,我写了大约25行代码来获取对象(在复制之前列出所有工作表,列出所有工作表之后,并找出哪一个只在最后一个列表中。所有在VBA中非常冗长),但我正在寻找更优雅,更短的解决方案。
Dim sht
With ActiveWorkbook
.Sheets("Sheet1").Copy After:= .Sheets("Sheet2")
Set sht = .Sheets(.Sheets("Sheet2").Index + 1)
End With
基于Trevor Norman's method,我开发了一个复制工作表并返回对新工作表的引用的功能。
码:
Function CopySheet(ByRef sourceSheet As Worksheet, Optional ByRef destinationWorkbook As Workbook) As Worksheet
Dim newSheet As Worksheet, lastSheet As Worksheet
Dim lastIsVisible As Boolean
If destinationWorkbook Is Nothing Then Set destinationWorkbook = sourceSheet.Parent
With destinationWorkbook
Set lastSheet = .Worksheets(.Worksheets.Count)
End With
lastIsVisible = lastSheet.Visible
lastSheet.Visible = True
sourceSheet.Copy After:=lastSheet
Set newSheet = lastSheet.Next
If Not lastIsVisible Then lastSheet.Visible = False
Set CopySheet = newSheet
End Function
这将始终将复制的工作表插入目标工作簿的末尾。
在此之后,您可以进行任何移动,重命名等。
用法:
Sub Sample()
Dim newSheet As Worksheet
Set newSheet = CopySheet(ThisWorkbook.Worksheets("Template"))
Debug.Print newSheet.Name
newSheet.Name = "Sample" ' rename new sheet
newSheet.Move Before:=ThisWorkbook.Worksheets(1) ' move to beginning
Debug.Print newSheet.Name
End Sub
或者,如果您希望行为/接口更类似于内置的Copy方法(即之前/之后),您可以使用:
Function CopySheet2(ByRef sourceSheet As Worksheet, Optional ByRef beforeSheet As Worksheet, Optional ByRef afterSheet As Worksheet) As Worksheet
Dim destinationWorkbook As Workbook
Dim newSheet As Worksheet, lastSheet As Worksheet
Dim lastIsVisible As Boolean
If Not beforeSheet Is Nothing Then
Set destinationWorkbook = beforeSheet.Parent
ElseIf Not afterSheet Is Nothing Then
Set destinationWorkbook = afterSheet.Parent
Else
Set destinationWorkbook = sourceSheet.Parent
End If
With destinationWorkbook
Set lastSheet = .Worksheets(.Worksheets.Count)
End With
lastIsVisible = lastSheet.Visible
lastSheet.Visible = True
sourceSheet.Copy After:=lastSheet
Set newSheet = lastSheet.Next
If Not lastIsVisible Then lastSheet.Visible = False
If Not beforeSheet Is Nothing Then
newSheet.Move Before:=beforeSheet
ElseIf Not afterSheet Is Nothing Then
newSheet.Move After:=afterSheet
Else
newSheet.Move After:=sourceSheet
End If
Set CopySheet2 = newSheet
End Function
正如这里已经提到的,将工作表复制/粘贴到最左边(index = 1),然后将其分配给变量,然后将其移动到您想要的位置。粘贴纸张Before
意味着您无需验证并可能取消隐藏任何纸张。
我现在无法测试,但我不明白为什么它不起作用。 :)
Function CopyWorksheet(SourceWorksheet as Worksheet, AfterDestinationWorksheet as Worksheet) as Worksheet
SourceWorksheet.Copy Before:= AfterDestinationWorksheet.Parent.Sheets(1)
Dim NewWorksheet as Worksheet
Set NewWorksheet = AfterDestinationWorksheet.Parent.Sheets(1)
NewWorksheet.Move After:= AfterDestinationWorksheet
Return NewWorksheet
End Function
我相信我终于把这个问题钉在了一起 - 这也让我疯了!如果MS制作Copy会返回一个工作表对象,就像添加方法一样,这真的很不错......
事实上,VBA分配新复制的工作表的索引实际上没有确定......正如其他人所指出的那样,它在很大程度上取决于隐藏的工作表。事实上,我认为表达式Sheets(n)实际上被解释为“第n个可见表”。因此,除非你编写一个循环测试每个工作表的可见属性,否则在代码中使用它会充满危险,除非工作簿受到保护,因此用户不能弄乱工作表可见属性。太难...
我对这种困境的解决方案是:
这是我的代码 - 现在似乎是防弹......
Dim sh as worksheet
Dim last_is_visible as boolean
With ActiveWorkbook
last_is_visible = .Sheets(.Sheets.Count).Visible
.Sheets(Sheets.Count).Visible = True
.Sheets("Template").Copy After:=.Sheets(Sheets.Count)
Set sh=.Sheets(Sheets.Count)
if not last_is_visible then .Sheets(Sheets.Count-1).Visible = False
sh.Move After:=.Sheets("OtherSheet")
End With
在我的情况下,我有这样的事情(H表示隐藏的表格)
1 ... 2 ... 3(H)... 4(H)... 5(H)... 6 ... 7 ... 8(H)... 9(H)
.Copy After:=。Sheets(2)实际上在下一个VISIBLE工作表之前创建了一个新工作表 - 也就是说,它成为新的索引6.而不是索引3,正如您所料。
希望有所帮助;-)
我使用的另一个解决方案是将工作表复制到您知道其索引的位置,即第一个。在那里,您可以轻松地根据需要随意引用它,之后您可以将其自由移动到您想要的位置。
像这样的东西:
Worksheets("Sheet1").Copy before:=Worksheets(1)
set newSheet = Worksheets(1)
newSheet.move After:=someSheet
更新:
Dim ThisSheet As Worksheet
Dim NewSheet As Worksheet
Set ThisSheet = ActiveWorkbook.Sheets("Sheet1")
ThisSheet.Copy
Set NewSheet = Application.ActiveSheet
我意识到这篇文章已经有一年多了,但是我来到这里寻找一个关于复制工作表和隐藏工作表引起的意外结果的相同问题的答案。由于我的工作簿结构,上述所有内容都不适合我想要的内容。 Essentailly它有非常多的工作表,显示的内容是由用户选择特定功能驱动的,加上可见工作表的顺序是importnat给我,所以我不想搞砸那些。所以我的最终解决方案是依靠复制工作表的Excel默认命名约定,并明确地按名称重命名新工作表。下面的代码示例(另外,我的工作簿有42张,只有7张永久可见,而after:=Sheets(Sheets.count)
将我复制的纸张放在42张纸的中间,具体取决于当时可见的纸张。
Select Case DCSType
Case "Radiology"
'Copy the appropriate Template to a new sheet at the end
TemplateRAD.Copy after:=Sheets(Sheets.count)
wsToCopyName = TemplateRAD.Name & " (2)"
'rename it as "Template"
Sheets(wsToCopyName).Name = "Template"
'Copy the appropriate val_Request to a new sheet at the end
valRequestRad.Copy after:=Sheets(Sheets.count)
'rename it as "val_Request"
wsToCopyName = valRequestRad.Name & " (2)"
Sheets(wsToCopyName).Name = "val_Request"
Case "Pathology"
'Copy the appropriate Template to a new sheet at the end
TemplatePath.Copy after:=Sheets(Sheets.count)
wsToCopyName = TemplatePath.Name & " (2)"
'rename it as "Template"
Sheets(wsToCopyName).Name = "Template"
'Copy the appropriate val_Request to a new sheet at the end
valRequestPath.Copy after:=Sheets(Sheets.count)
wsToCopyName = valRequestPath.Name & " (2)"
'rename it as "val_Request"
Sheets(wsToCopyName).Name = "val_Request"
End Select
无论如何,张贴以防万一对其他人有用
这应该是对@TimWilliams的回应,但这是我的第一篇帖子,所以我无法发表评论。
这是@RBarryYoung提到的与隐藏表相关的问题的一个例子。当您尝试将副本放在最后一个工作表之后并且隐藏最后一个工作表时,会出现问题。看来,如果最后一张纸被隐藏,它总是保留最高的索引,所以你需要类似的东西
Dim sht As Worksheet
With ActiveWorkbook
.Sheets("Sheet1").Copy After:=.Sheets(.Sheets.Count)
Set sht = .Sheets(.Sheets.Count - 1)
End With
当您尝试在隐藏的第一个工作表之前复制时的类似情况。
更新了Daniel Labelle的建议:
要处理可能的隐藏工作表,请使源工作表可见,复制它,使用ActiveSheet
方法将引用返回到新工作表,然后重置可见性设置:
Dim newSheet As Worksheet
With ActiveWorkbook.Worksheets("Sheet1")
.Visible = xlSheetVisible
.Copy after:=someSheet
Set newSheet = ActiveSheet
.Visible = xlSheetHidden ' or xlSheetVeryHidden
End With
隐藏的工作表是正确的,导致新工作表索引在源工作表的任一侧是非顺序的。我发现如果你以前复制过,Rachel的答案是有效的。但如果您正在复制,则必须对其进行调整。
一旦模型可见并被复制,无论您是在之前还是之后复制源,新工作表对象都只是ActiveSheet。
作为首选项,您可以替换:
使用“Set newSheet = Application.ActiveSheet”设置“newSheet = .Previous”。
希望这对你们中的一些人有所帮助。
我一直在尝试为sheet.Copy方法创建一个可靠的通用“包装”函数,以便在多个项目中重复使用多年。
我在这里尝试了几种方法,我发现只有Mark Moore的答案才能成为所有场景的可靠解决方案。即使用“Template(2)”名称来识别新工作表的那个。
就我而言,使用“ActiveSheet方法”的任何解决方案都是无用的,因为在某些情况下,目标工作簿位于非活动或隐藏的工作簿中。
同样,我的一些工作簿中隐藏的纸张与不同位置的可见纸张混合在一起;在开始,在中间,在结尾;因此我发现使用Before:和After:选项的解决方案也不可靠,具体取决于可见和隐藏工作表的排序,以及源工作表也被隐藏时的附加因素。
因此,在几次重写之后,我最终得到了以下包装函数:
'***************************************************************************
'This is a wrapper for the worksheet.Copy method.
'
'Used to create a copy of the specified sheet, optionally set it's name, and return the new
' sheets object to the calling function.
'
'This routine is needed to predictably identify the new sheet that is added. This is because
' having Hidden sheets in a Workbook can produce unexpected results in the order of the sheets,
' eg when adding a hidden sheet after the last sheet, the new sheet doesn't always end up
' being the last sheet in the Worksheets collection.
'***************************************************************************
Function wsCopy(wsSource As Worksheet, wsAfter As Worksheet, Optional ByVal sNewSheetName As String) As Worksheet
Dim Ws As Worksheet
wsSource.Copy After:=wsAfter
Set Ws = wsAfter.Parent.Sheets(wsSource.Name & " (2)")
'set ws Name if one supplied
If sNewSheetName <> "" Then
Ws.Name = sNewSheetName
End If
Set wsCopy = Ws
End Function
注意:如果源表的名称超过27个字符,即使此解决方案也会出现问题,因为最大工作表名称为31,但这通常由我控制。