【问题标题】:How do I reference charts with the same name, but on different worksheets?如何引用具有相同名称但在不同工作表上的图表?
【发布时间】:2016-09-17 14:52:01
【问题描述】:

我有两个包含图表的工作表,并使用宏遍历所有包含图表的工作表并更新图表值。

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

循环如下所示:

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

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

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

【问题讨论】:

  • 我无法复制这个。它在 Excel 2010 上运行良好。您使用的是什么版本?
  • @BrettWolfington 2013
  • 不能使用嵌套循环吗?像这样:For Each ws In ThisWorkbook.Worksheets For Each co In ws.ChartObjects ... Next co Next ws
  • @tom 我刚试了一下,还是一样的错误。
  • 不应该这样称呼它ch.Chart.Name。请参阅下面的答案。

标签: vba excel


【解决方案1】:

正如您所发现的,Workheet.ChartObjects 方法将找到正确的 ChartObject,但访问 Chartobject.Chart 属性将返回 ActiveSheet 的图表。无论您是按名称还是按索引编号引用 ChartObject。

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

此行为与早期版本的 Excel 不同。我确认该代码在 Excel XP/2002 中有效,但在 2016 年无效。我不确定行为何时发生变化。可能是 2013 年,或者可能是 2013 年和 2016 年的补丁? Office for 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
    

    测试

    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】:

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

      说清楚

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

      因此,Worksheet.ChartObject.ChartChart 工作表的不同之处如下:

      • 来自Worksheet.ChartObject.ChartChart 包含图表的所有属性。
      • Chart 工作表包含图表的所有属性和工作表的一些属性。

      所以.Name 属性应该用于Chart 工作表而不是Worksheet.ChartObject.Chart

      我会说在调用ChartObject.Chart.Name 时额外显示活动表名称不是错误,而是已调试错误。 ChartObject.Chart 首先不会也不应该有Name。您可以调用ChartObject.Chart.Name,因为Chart 的对象模型的智能感知中有重叠。如果 Microsoft 不允许这样做,就会出现错误。

      简而言之,请记住图表没有名称,带有名称的是ChartObjectSheet。相比之下,一个图表有ChartTitle

      【讨论】:

      • 呃……我的回答被否决了。我当然花了很多时间研究这个,但没什么大不了的。无论如何,如果答案有任何问题,请告诉我,我很乐意进行更正.. Tks!
      猜你喜欢
      • 2021-08-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多