How do I reference charts with the same name, but on different worksheets?

后端 未结 3 683
渐次进展
渐次进展 2021-01-04 10:32

I have two worksheets containing charts, and use a macro to run over all the sheets with charts in them and update the values charted.

However, I run into a problem

相关标签:
3条回答
  • 2021-01-04 10:48

    There is a difference between Chart and Worksheet.ChartObject.Chart.

    Make it clear that

    • When you create a chart in a worksheet, Excel creates a ChartObject to contain the Chart. So the Chart is a child of ChildObject which in turn is a child of Worksheet.
    • When you create a chart as a sheet, it is a Chart (or you may call it "chart sheet") equivalent to a Worksheet.

    Therefore a Worksheet.ChartObject.Chart is different from a Chart sheet in the following way:

    • A Chart from Worksheet.ChartObject.Chart contains all the properties of a chart.
    • A Chart sheet contains all the properties of a chart AND some properties of a sheet.

    So the .Name property is supposed to be for Chart sheet but not for Worksheet.ChartObject.Chart.

    I'd say the additional display of the activesheet name when calling ChartObject.Chart.Name is not a bug but a debugged bug. ChartObject.Chart wouldn't and shouldn't have a Name in the first place. You can call ChartObject.Chart.Name because there is an overlapping in the intellisense for object model of Chart. Had Microsoft hasn't allow for this, there would be a bug.

    So in short, remember that a chart has no name, it is the ChartObject or the Sheet that carries the name. To contrast this, a chart has ChartTitle.

    0 讨论(0)
  • 2021-01-04 11:03

    As you've discovered, the Workheet.ChartObjects method will find the correct ChartObject, but accessing the Chartobject.Chart property will return the Chart of the ActiveSheet. It doesn't matter if you refer to the ChartObject by name or by Index number.

    The behavior is the same if you use the Worksheet.Shapes method to find the ChartObject.

    This behavior is different to earlier versions of Excel. I confirmed that the code worked in Excel XP/2002, and doesn't work in 2016. I'm unsure when the behavior changed. It might have been 2013, or it might have been a patch to 2013 and 2016? The behavior in Office for mac 2016 is the same (ie. doesn't work)

    Until Microsoft comes up with a fix, you'll have to activate the sheet, or activate the ChartObject, before you access the Chart property.

    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
    

    I suggest that you temporarily disable ScreenUpdating, and reactivate the originally activesheet once you're done.

    0 讨论(0)
  • 2021-01-04 11:07

    GetChart will return the chart object on a specific worksheet.

    getChart stores the chart objects in a Static Collection. The Static Collection will stay in memory until there is a code break or the workbook is closed.

    The first time that you call getChart all the Chart Objects all the each worksheet is activated and each chart on each worksheet is added to the collection. After that the chart is merely lookup up in the static collection.

    In the case that a chart (e.g. a chart was added after the function was called) isn't in the collection the function will reload itself.

    Get Chart

    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
    
    0 讨论(0)
提交回复
热议问题