如何引用具有相同名称但在不同工作表上的图表?

时间:2016-08-12 11:04:38

标签: excel vba excel-vba

我有两个包含图表的工作表,并使用宏来运行包含图表的所有工作表,并更新图表中的值。

但是,在尝试在第一个工作表之后引用工作表中的图表时遇到问题 - 尽管工作表的引用发生了更改,但对图表的引用却没有。

循环如下:

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

- 编辑 - 我现在根据评论中的建议进行了一些测试,看来打印到即时窗口的内容取决于当前活动工作表的内容。

尝试使用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
...

3 个答案:

答案 0 :(得分:5)

正如您所发现的,Workheet.ChartObjects方法将找到正确的ChartObject,但访问Chartobject.Chart属性将返回ActiveSheet的图表。如果按名称或索引号引用ChartObject,则无关紧要。

如果使用Worksheet.Shapes方法查找ChartObject,行为是相同的。

此行为与早期版本的Excel不同。我确认代码在Excel XP / 2002中有效,并且在2016年不起作用。我不确定行为何时发生变化。它可能是2013年,或者它可能是2013年和2016年的补丁? Office for Mac 2016中的行为是相同的(即不起作用)

在Microsoft提出修复之前,您必须激活工作表,或者在访问Chart属性之前激活ChartObject

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,并在完成后重新激活原始活动表。

答案 1 :(得分:1)

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

测试

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

答案 2 :(得分:0)

ChartWorksheet.ChartObject.Chart之间存在差异。

明确表示

  • 当您在工作表中创建图表时,Excel会创建ChartObject以包含Chart。因此,ChartChildObject的孩子,后者又是Worksheet的孩子。
  • 当您将图表创建为工作表时,它是Chart(或者您可以称之为“图表工作表”),相当于Worksheet

因此,Worksheet.ChartObject.ChartChart表格的区别在于以下方式:

  • Chart中的Worksheet.ChartObject.Chart包含图表的所有属性。
  • Chart工作表包含图表的所有属性和工作表的某些属性。

因此.Name属性应该是Chart表,而不是Worksheet.ChartObject.Chart

我要说调用ChartObject.Chart.Name时附加显示活动表名称不是错误,而是调试错误。 ChartObject.Chart首先不会也不应该有Name。您可以调用ChartObject.Chart.Name,因为Chart的对象模型的intellisense中存在重叠。如果微软不允许这样做,就会有一个错误。

简而言之,请记住图表没有名称,ChartObjectSheet带有名称。为了对比,图表有ChartTitle