Existe-t-il un moyen easy/short d'obtenir l'objet Excel.worksheet de la feuille new que vous obtenez lorsque vous copiez une feuille de calcul?
ActiveWorkbook.Sheets("Sheet1").Copy after:=someSheet
Il s'avère que la méthode .Copy renvoie un booléen au lieu d'un objet de feuille de calcul. Sinon, j'aurais pu faire:
set newSheet = ActiveWorkbook.Sheets("Sheet1").Copy after:=someSheet <-- doesn't work
J'ai donc écrit environ 25 lignes de code pour obtenir l'objet (lister toutes les feuilles avant la copie, lister toutes les feuilles après, et trouver celle qui ne figure que dans la dernière liste. Toutes très longues en VBA), mais je cherche une solution plus élégante et plus courte.
Dim sht
With ActiveWorkbook
.Sheets("Sheet1").Copy After:= .Sheets("Sheet2")
Set sht = .Sheets(.Sheets("Sheet2").Index + 1)
End With
Je crois avoir enfin résolu le problème. Cela m'a rendu fou aussi! Ce serait vraiment bien si MS faisait copier par Copy un objet de feuille identique à la méthode Add ...
Le problème est que l’index attribué par VBA à une feuille récemment copiée n’est en fait pas déterminé ... comme d’autres l'ont déjà noté, cela dépend beaucoup des feuilles cachées. En fait, je pense que l'expression Sheets (n) est en fait interprétée comme "la nième feuille visible". Par conséquent, à moins d'écrire une boucle testant la propriété visible de chaque feuille, son utilisation dans le code présente un danger, à moins que le classeur ne soit protégé afin que les utilisateurs ne puissent pas jouer avec la propriété visible des feuilles. Trop dur...
Ma solution à ce dilemme est la suivante:
Voici mon code - qui semble maintenant être à l'épreuve des balles ...
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
Dans mon cas, j'avais quelque chose comme ça (H indiquant une feuille cachée)
1 ... 2 ... 3 (H) ... 4 (H) ... 5 (H) ... 6 ... 7 ... 8 (H) ... 9 (H)
.Copie après: =. Sheets (2) crée une nouvelle feuille AVANT la feuille suivante VISIBLE - c’est-à-dire qu’il est devenu le nouvel index 6. PAS à l’index 3, comme on pouvait s’y attendre.
J'espère que cela pourra aider ;-)
Une autre solution que j'ai utilisée serait de copier la feuille dans un endroit où vous connaissez son index, c'est-à-dire son premier. Là, vous pouvez facilement y trouver une référence pour tout ce dont vous avez besoin, puis vous pouvez le déplacer librement où vous le souhaitez.
Quelque chose comme ça:
Worksheets("Sheet1").Copy before:=Worksheets(1)
set newSheet = Worksheets(1)
newSheet.move After:=someSheet
METTRE À JOUR:
Dim ThisSheet As Worksheet
Dim NewSheet As Worksheet
Set ThisSheet = ActiveWorkbook.Sheets("Sheet1")
ThisSheet.Copy
Set NewSheet = Application.ActiveSheet
Je me rends compte que cet article date de plus d'un an, mais je suis venu ici pour chercher une réponse au même problème concernant la copie de feuilles et les résultats inattendus causés par des feuilles cachées. Rien de ce qui précède ne convenait vraiment à ce que je voulais principalement à cause de la structure de mon cahier de travail. Essentailly a un très grand nombre de feuilles et ce qui est affiché est déterminé par un utilisateur qui sélectionne une fonctionnalité spécifique. De plus, l'ordre des feuilles visibles était important pour moi, donc je ne voulais pas jouer avec celles-ci. Ma solution finale consistait donc à utiliser la convention de nommage par défaut d'Excel pour les feuilles copiées et à renommer explicitement la nouvelle feuille par son nom. Échantillon de code ci-dessous (à part, mon cahier a 42 feuilles et seules 7 sont visibles en permanence, et le after:=Sheets(Sheets.count)
place ma feuille copiée au milieu des 42 feuilles, en fonction des feuilles visibles au début. temps.
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
Quoi qu'il en soit, posté juste au cas où il serait utile à quelqu'un d'autre
Mis à jour avec les suggestions de Daniel Labelle:
Pour gérer d'éventuelles feuilles masquées , rendez la feuille source visible, copiez-la, utilisez la méthode ActiveSheet
pour renvoyer la référence à la nouvelle feuille et réinitialisez les paramètres de visibilité:
Dim newSheet As Worksheet
With ActiveWorkbook.Worksheets("Sheet1")
.Visible = xlSheetVisible
.Copy after:=someSheet
Set newSheet = ActiveSheet
.Visible = xlSheetHidden ' or xlSheetVeryHidden
End With
Cela devrait être un commentaire en réponse à @TimWilliams, mais c'est mon premier post donc je ne peux pas commenter.
Voici un exemple du problème mentionné par @RBarryYoung, lié aux feuilles masquées. Il y a un problème lorsque vous essayez de placer votre copie après la dernière feuille et que celle-ci est masquée. Il semble que, si la dernière feuille est masquée, elle conserve toujours l’index le plus élevé;
Dim sht As Worksheet
With ActiveWorkbook
.Sheets("Sheet1").Copy After:=.Sheets(.Sheets.Count)
Set sht = .Sheets(.Sheets.Count - 1)
End With
Situation similaire lorsque vous essayez de copier avant une première feuille masquée.
Il est exact que les feuilles de calcul masquées font en sorte que le nouvel index de la feuille de calcul ne soit pas séquentiel de part et d'autre de la feuille de calcul source. J'ai trouvé que la réponse de Rachel fonctionnait si vous copiez avant. Mais vous devrez l’ajuster si vous copiez après.
Une fois que le modèle est visible et copié, le nouvel objet de la feuille de calcul est simplement la feuille ActiveSheet, que vous copiiez la source avant ou après.
De préférence, vous pouvez remplacer:
"Définissez newSheet = .Previous" avec "Définissez newSheet = Application.ActiveSheet".
J'espère que cela sera utile à certains d'entre vous.
Basé sur la méthode de Trevor Norman , j'ai développé une fonction permettant de copier une feuille et de renvoyer une référence à la nouvelle feuille.
Code:
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
Cela insérera toujours la feuille copiée à la fin du classeur de destination.
Après cela, vous pouvez faire n'importe quels mouvements, renommer, etc.
Usage:
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
Ou si vous souhaitez que le comportement/l'interface ressemble davantage à la méthode Copy intégrée (c'est-à-dire avant/après), vous pouvez utiliser:
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
J'ai essayé de créer une fonction "wrapper" générique fiable pour la méthode sheet.Copy à réutiliser dans plusieurs projets pendant des années.
J'ai essayé plusieurs des approches ici et je n'ai trouvé que la réponse de Mark Moore était une solution fiable dans tous les scénarios. C'est-à-dire celui qui utilise le nom "Template (2)" pour identifier la nouvelle feuille.
Dans mon cas, toute solution utilisant la "méthode ActiveSheet" était inutile car, dans certains cas, le classeur cible se trouvait dans un classeur non actif ou masqué.
De même, certains de mes cahiers ont des feuilles masquées mélangées à des feuilles visibles à divers endroits; au début, au milieu, à la fin; et donc j'ai trouvé les solutions en utilisant les options Avant: et Après: également peu fiables en fonction de l'ordre des feuilles visibles et masquées, ainsi que du facteur supplémentaire lorsque la feuille source est également masquée.
Par conséquent, après plusieurs réécritures, j'ai fini avec la fonction d'emballage suivante:
'***************************************************************************
'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
Remarque: même cette solution aura des problèmes si le nom de la feuille source est plus de 27 caractères, car le nom maximum de la feuille est 31, mais c'est généralement sous mon contrôle.