Как мне сопоставлять диаграммы с тем же именем, но на разных листах?

У меня есть два рабочих листа, содержащих диаграммы, и используйте макрос для запуска по всем листам с диаграммами в них и обновляйте значения, указанные на рисунке.

Однако я столкнулся с проблемой при попытке ссылаться на диаграммы в листах после первого - хотя ссылка на рабочий лист меняется, ссылка на диаграмму не соответствует.

Цикл выглядит следующим образом:

For Each ws In ThisWorkbook.Worksheets
  Debug.Print ws.Name
  Debug.Print ws.ChartObjects("Kortsone").Chart.Name
  With ws.ChartObjects("Kortsone").Chart
    ...
  End With
Next ws

И вывод, который я получаю в ближайшее окно, следующий:

Grafar ovn 3
Grafar ovn 3 Kortsone
Grafar ovn 4
Grafar ovn 3 Kortsone

Как вы можете видеть ссылку на изменения листа, но ссылка на диаграмму не указана.

Есть ли способ исправить это, или мне нужно переименовать все мои диаграммы с уникальными именами?

Я использую Excel 2013

- edit - Я уже провел некоторое тестирование на основе предложений в комментариях, и кажется, что то, что напечатано в непосредственном окне, зависит от того, что в настоящее время является активным листом.

Попытка использовать for each chartobject столкнулась с теми же проблемами, что и раньше:

Sub test2()
  Dim ws As Worksheet
  Dim ch As ChartObject

  For Each ws In ThisWorkbook.Worksheets
    For Each ch In ws.ChartObjects
      If ws.CodeName = "Graf4" Then
      Debug.Print ws.Name
      Debug.Print ch.Name
      Debug.Print ch.Chart.Name
      End If
    Next ch
  Next ws
End Sub

Дал:

Grafar ovn 4
Kortsone
Grafar ovn 3 Kortsone
Grafar ovn 4
Langsone
Grafar ovn 3 Langsone
...

Ответ 1

Как вы обнаружили, метод Workheet.ChartObjects найдет правильный ChartObject, но доступ к свойству Chartobject.Chart вернет диаграмму ActiveSheet. Не имеет значения, ссылаетесь ли вы на объект ChartObject по имени или по индексу.

Поведение такое же, если вы используете метод Worksheet.Shapes для поиска ChartObject.

Такое поведение отличается от предыдущих версий Excel. Я подтвердил, что код работал в Excel XP/2002 и не работает в 2016 году. Я не уверен, когда поведение изменилось. Возможно, это было 2013 год, или это мог быть патч к 2013 и 2016 годам? Поведение в Office для mac 2016 одинаково (т.е. Не работает)

Пока Microsoft не придумает исправление, вам нужно активировать лист или активировать ChartObject, прежде чем вы получите доступ к свойству Chart.

Sub test()
  Dim ws As Worksheet
  Dim co As ChartObject
  For Each ws In ThisWorkbook.Worksheets
    Debug.Print ws.Name
    Set co = ws.ChartObjects("Kortsone")

    ws.Activate
    'or
    co.Activate

    Debug.Print co.Chart.Name
    With ws.ChartObjects("Kortsone").Chart
    End With
  Next ws
End Sub

Я предлагаю вам временно отключить ScreenUpdating и повторно активировать исходную таблицу действий после того, как вы закончите.

Ответ 2

GetChart вернет объект диаграммы на конкретном листе.

getChart хранит объекты диаграммы в Static Collection. Static Collection останется в памяти до тех пор, пока не будет сломан код или книга не будет закрыта.

В первый раз, когда вы вызываете getChart все объекты диаграммы, каждая рабочая таблица активируется, и каждая диаграмма на каждом рабочем листе добавляется в коллекцию. После этого диаграмма просто ищет статическую коллекцию.

В случае, когда диаграмма (например, диаграмма была добавлена ​​после вызова функции) не находится в коллекции, функция перезагрузится.

Получить график

Function getChart(ChartName As String, WorkSheetName As String, Optional Reload As Boolean) As Chart
    Dim ws As Worksheet, ActiveWS As Worksheet
    Dim co As ChartObject
    Static ChartCollection As Collection

    If ChartCollection Is Nothing Or Reload Then
        Application.ScreenUpdating = False

        Set ChartCollection = New Collection
        Set ActiveWS = ActiveSheet
        For Each ws In ThisWorkbook.Worksheets
            ws.Activate
            For Each co In ws.ChartObjects
                ChartCollection.Add co.Chart, ws.Name & "!" & co.Name
            Next
        Next ws

        ActiveWS.Activate
        Application.ScreenUpdating = True
    End If

    On Error Resume Next
    Set getChart = ChartCollection(WorkSheetName & "!" & ChartName)

    If Err.Number <> 0 And Not Reload Then Set getChart = getChart(ChartName, WorkSheetName, True)

    On Error GoTo 0

End Function

Test

Sub Test()
    Dim ws As Worksheet
    Dim ch As Chart
    Dim msg As String
    Dim Start: Start = Timer

    For Each ws In ThisWorkbook.Worksheets
        Set ch = getChart("Kortsone", ws.Name)
        If Not ch Is Nothing Then

            msg = msg & ws.Name & "!" & ch.Name & " - Validated:" & (ws.Name = ch.Parent.Parent.Name) & vbCrLf

        End If
    Next ws
    msg = msg & "Time in Seconds: " & Timer - Start
    MsgBox msg
End Sub

Ответ 3

Существует разница между Chart и Worksheet.ChartObject.Chart.

Выясните, что

  • Когда вы создаете таблицу в, Excel создает ChartObject, чтобы содержать Chart. Таким образом, Chart является дочерним элементом ChildObject, который, в свою очередь, является дочерним элементом Worksheet.
  • Когда вы создаете таблицу как, это Chart (или вы можете называть ее "лист диаграммы" ), эквивалентный Worksheet.

Поэтому a Worksheet.ChartObject.Chart отличается от листа Chart следующим образом:

  • A Chart from Worksheet.ChartObject.Chart содержит все свойства диаграммы.
  • Лист Chart содержит все свойства диаграммы и некоторые свойства листа.

Таким образом, свойство .Name должно быть для листа Chart, но не для Worksheet.ChartObject.Chart.

Я бы сказал, что дополнительное отображение имени activesheet при вызове ChartObject.Chart.Name не является ошибкой, а отлаженной ошибкой. ChartObject.Chart не будет и не должен иметь Name в первую очередь. Вы можете вызвать ChartObject.Chart.Name, потому что в объектной модели Chart есть перекрытие в объектной модели intellisense. Если бы Microsoft не допустила этого, была бы ошибка.

Итак, помните, что диаграмма не имеет имени, это ChartObject или Sheet, которое несет имя. Чтобы сопоставить это, диаграмма имеет ChartTitle.