4
votes

Copie de graphiques avec VBA: impossible de supprimer ou de modifier les copies

J'utilise Excel sur MacOS. Les informations "À propos de" me disent qu'il s'agit de la version 16.16.5, qui correspond apparemment à Office 2016. Si vous regardez le code ici et pensez "hé, ça marche pour moi", ce serait formidable si vous pouviez laisser un commentaire qui inclut la version d'Excel que vous utilisez.

J'ai une feuille de calcul dans laquelle je voudrais copier des graphiques d'une feuille de calcul "modèle" dans env. 80 autres feuilles de calcul, puis modifiez-les pour faire référence aux données de la feuille de destination plutôt qu'à la feuille d'origine (via une simple recherche et remplacement sur la série).

Cela ne semble pas à première vue tout cela est difficile, et il y a beaucoup de solutions potentielles à la fois ici sur Stack Overflow et ailleurs, mais je semble continuer à rencontrer un comportement inattendu.

Pour les exemples ci-dessous, le code copie simplement les graphiques d'une feuille de calcul vers un autre, plutôt que d'itérer sur toutes les feuilles de calcul disponibles, car cela facilite le nettoyage en cas d'échec. Ce qui, jusqu'à présent, l'est toujours.

Tentative n ° 1

Ma première tentative ressemblait à ceci:

        For Each chSeries In newChartObj.Chart.SeriesCollection

Cela fonctionne presque : il copie en fait les graphiques dans la feuille de calcul de destination. Cependant, il échoue à cette ligne:

Sub Copy_Charts()
    Dim DataSheetName1 As String, DataSheetName2 As String
    Dim sourceChartSheet As Worksheet, destChartSheet As Worksheet
    Dim chartObj As ChartObject, newChartObj As ChartObject
    Dim chartObjCopy As ChartObject
    Dim chSeries As Series
    Dim chartIndex As Integer

    DataSheetName1 = "CU-2"
    DataSheetName2 = "CU-8"

    Set sourceChartSheet = Sheets("CU-2")
    Set destChartSheet = Sheets("CU-8")

    For Each chartObj In sourceChartSheet.ChartObjects
        ' No idea why chartObj.Duplicate returns something other
        ' than a ChartObject.
        Set newChartObj = chartObj.Duplicate.Chart.Parent
        newChartObj.Top = chartObj.Top
        newChartObj.Left = chartObj.Left
        newChartObj.Chart.Location xlLocationAsObject, destChartSheet.Name

        For Each chSeries In newChartObj.Chart.SeriesCollection
            chSeries.FormulaR1C1 = Replace(chSeries.FormulaR1C1, DataSheetName1, DataSheetName2)
        Next

    Next chartObj

End Sub

L'erreur est "Erreur d'exécution '1004': Erreur définie par l'application ou définie par l'objet".

Et en fait, si vous regardez destChartSheet.ChartObjects.Count à ce stade, il s'affiche toujours comme 0 . De plus, si vous essayez de supprimer les graphiques en utilisant un code comme celui-ci:

Sub Delete_Charts()
  Dim sht As Worksheet

  For Each sht In ActiveWorkbook.Worksheets
      If sht.Name <> "CU-2" Then
      If sht.ChartObjects.Count >= 1 Then
              sht.ChartObjects.Delete
              End If
      End If
  Next sht
End Sub

Cela ne supprimera pas réellement les graphiques. Le même code de suppression fonctionne très bien si vous copiez et collez les graphiques à la main.

En résumé: ce code copie les graphiques, mais je ne peux pas obtenir de référence à la copie afin de le modifier , je ne peux pas non plus le supprimer.

Tentative n ° 2

J'ai décidé de lancer le copier-coller hors de la fenêtre et d'essayer la méthode Duplicate à la place. Je me suis retrouvé avec ce qui suit:

        Set chartObjCopy = destChartSheet.ChartObjects(chartIndex)

Cela fonctionne (et échoue) différemment de la première solution: il copie aussi les graphiques dans la feuille de calcul cible , et contrairement à l'exemple précédent, il est possible de supprimer ces graphiques en utilisant cette sous-routine Delete_Charts .

Malheureusement, ce code échoue à:

Sub Copy_Charts()
  Dim DataSheetName1 As String, DataSheetName2 As String
  Dim chartObj as ChartObject, chartObjCopy as ChartObject
  Dim sourceChartSheet as Worksheet, destChartSheet as Worksheet

  DataSheetName1 = "CU-2"
  DataSheetName2 = "CU-8"

  Set sourceChartSheet = Sheets(DataSheetName1)
  Set destChartSheet = Sheets(DataSheetName2)

  For Each chartObj In sourceChartSheet.ChartObjects

          chartObj.Copy
          destChartSheet.Range(chartObj.TopLeftCell.Address).PasteSpecial xlPasteAll
          chartIndex = chartIndex + 1
          Set chartObjCopy = destChartSheet.ChartObjects(chartIndex)
          chartObjCopy.Left = chartObj.Left
          chartObjCopy.Top = chartObj.Top
  Next chartObj

End Sub


2 commentaires

La création de nouveaux objets de graphique fonctionnerait-elle pour vous? Il serait plus facile de créer de nouveaux graphiques dans votre feuille de destination en fonction des données de la feuille source.


Vous voulez dire créer de nouveaux graphiques via VBA? Cela pourrait être une meilleure solution à long terme, mais en ce moment, la duplication des graphiques nous donne plus de contrôle sur leur apparence sans avoir à apprendre à faire tout cela via VBA. Mais c'est quelque chose que nous avons envisagé :).


4 Réponses :


5
votes

Je pense que lorsque l'emplacement du graphique est déplacé, cela change la référence à l'objet graphique, ce qui entraîne l'échec de la collection de séries.

J'ai pu reproduire le problème, et le code ci-dessous fonctionne, mais je suis sur PC, donc je ne suis pas à 100% si des modifications supplémentaires seraient nécessaires pour être opérationnel sur Mac. Si vous déplacez cette ligne:

newChartObj.Chart.Location xlLocationAsObject, destChartSheet.Name

après la boucle SeriesCollection cela fonctionne , mais pas avant.

Option Explicit

Sub Copy_Charts()
    Dim DataSheetName1 As String, DataSheetName2 As String
    Dim sourceChartSheet As Worksheet, destChartSheet As Worksheet
    Dim chartObj As ChartObject, newChartObj As ChartObject
    Dim chartObjCopy As ChartObject
    Dim chSeries As Series

    DataSheetName1 = "CU-2"
    DataSheetName2 = "CU-8"

    Set sourceChartSheet = ThisWorkbook.Sheets(DataSheetName1)
    Set destChartSheet = ThisWorkbook.Sheets(DataSheetName2)

    For Each chartObj In sourceChartSheet.ChartObjects
         Set newChartObj = chartObj.Duplicate.Chart.Parent
        'Set newChartObj = chartObj 'Reference the sheet, good if you are cut/pasting the chart

        For Each chSeries In newChartObj.Chart.SeriesCollection
            chSeries.FormulaR1C1 = Replace(chSeries.FormulaR1C1, DataSheetName1, DataSheetName2)
        Next

        newChartObj.Top = chartObj.Top
        newChartObj.Left = chartObj.Left

        'Move this after the SeriesCollection loop
        newChartObj.Chart.Location xlLocationAsObject, destChartSheet.Name
    Next

End Sub


3 commentaires

Merci! J'ai une question: vous définissez newChartObj = chartObj . Il me semble que vous obtenez juste une deuxième référence au graphique d'origine, de sorte que dans les lignes suivantes, vous modifiez simplement le graphique d'origine et ne faites jamais de copie. Suis-je mal interprété cela?


Oui c'est vrai. J'ai mal compris votre demande, voyez la modification si vous voulez une copie.


La réponse de @ z32a7ul ( stackoverflow.com/a/54221244/147356 ) explique pourquoi les choses ne fonctionnent pas après la mise à jour du Propriété de localisation .



5
votes
Sub Copy_Charts()


    Dim DataSheetName1 As String, DataSheetName2 As String
    Dim sourceChartSheet As Worksheet, destChartSheet As Worksheet
    Dim chartObj As ChartObject, newChartObj As ChartObject
    Dim chartObjCopy As ChartObject
    Dim chSeries As Series
    Dim chartIndex As Integer

    DataSheetName1 = "CU-2"
    DataSheetName2 = "CU-8"

    Set sourceChartSheet = Sheets("CU-2")
    Set destChartSheet = Sheets("CU-8")

    For Each chartObj In sourceChartSheet.ChartObjects
        ' No idea why chartObj.Duplicate returns something other
        ' than a ChartObject.
        Set newChartObj = chartObj.Duplicate.Chart.Parent
        newChartObj.Top = chartObj.Top
        newChartObj.Left = chartObj.Left
        newChartObj.Chart.Location xlLocationAsObject, destChartSheet.Name

        'For Each chSeries In newChartObj.Chart.SeriesCollection
        '    chSeries.FormulaR1C1 = Replace(chSeries.FormulaR1C1, DataSheetName1, DataSheetName2)
        'Next

    Next chartObj

    For Each chartObj In destChartSheet.ChartObjects
        For Each chSeries In chartObj.Chart.SeriesCollection:
            chSeries.FormulaR1C1 = Replace(chSeries.FormulaR1C1, DataSheetName1, DataSheetName2)
        Next
    Next chartObj

End Sub
I tested it on my Mac, Excel: 16.20 and it works. It's just a slight change on your original code.

0 commentaires

2
votes

Je n'ai pas accès à un Mac, j'ai donc dû le tester sur Windows 10, Office 2016 mais j'ai pu reproduire l'erreur. Concernant votre tentative n ° 2, j'ai constaté que le problème est causé par la ligne ci-dessous:

Set newChartObj = newChartObj.Chart.Location(xlLocationAsObject, destChartSheet.Name).Parent

Cela a un effet secondaire: un nouveau graphique sera créé tandis que votre objet d'origine (référence) deviendra invalide, vous obtiendrez donc une erreur lorsque vous tenterez d'accéder à sa propriété SeriesCollection. Cependant, la fonction Location renvoie une référence au nouveau graphique, il vous suffit donc de mettre à jour votre newChartObj pour faire référence au nouveau graphique (au lieu de la ligne ci-dessus, mettez ceci dans votre code):

newChartObj.Chart.Location xlLocationAsObject, destChartSheet.Name


1 commentaires

Merci pour l'explication! Je ne m'attendais pas à ce que la modification de l'emplacement crée un nouvel objet; ce comportement ne semble pas être dans la documentation < / a>.



0
votes

Essayez

Sub Copy_Charts()
  Dim DataSheetName1 As String, DataSheetName2 As String
  Dim chartObj As ChartObject, chartObjCopy As ChartObject
  Dim sourceChartSheet As Worksheet, destChartSheet As Worksheet

  DataSheetName1 = "CU-2"
  DataSheetName2 = "CU-8"

  Set sourceChartSheet = Sheets(DataSheetName1)
  Set destChartSheet = Sheets(DataSheetName2)

  For Each chartObj In sourceChartSheet.ChartObjects

          chartObj.Copy
          destChartSheet.Paste
          'destChartSheet.Range(chartObj.TopLeftCell.Address).PasteSpecial xlPasteAll
          chartIndex = chartIndex + 1
          Set chartObjCopy = destChartSheet.ChartObjects(chartIndex)
          chartObjCopy.Left = chartObj.Left
          chartObjCopy.Top = chartObj.Top
  Next chartObj

End Sub


0 commentaires