VBA:提取图表中默认颜色线条的RGB值

10

问题

我想知道如何读取图表中自动分配颜色的当前RGB值,即使这意味着将颜色冻结为它们当前的值(而不是在更改主题、重新排序系列等情况下更新它们)。

用例

我的实际用例是希望数据标签与线条/标记的颜色匹配。如果我通过方案或显式RGB值明确设置系列的颜色,则很容易做到这一点,例如:

' assuming ColorFormat.Type = msoColorTypeRGB
s.DataLabels.Format.TextFrame2.TextRange.Font.Fill.ForeColor.RGB= _
s.Format.Line.ForeColor.RGB

然而,如果系列颜色是自动分配的,则执行此操作会导致标签变为白色。更具体地说,以下两个等式成立:
s.Format.Line.ForeColor.Type = msoColorTypeRGB 
s.Format.Line.ForeColor.RGB = RGB(255,255,255)  ' White

然而,这条线的颜色并不是白色的,而是从主题中自动分配的颜色。这表明该颜色是自动分配的。

s.Border.ColorIndex = xlColorIndexAutomatic

理所当然的是,颜色并没有与该系列一起存储。即使将索引存储到颜色方案中,通常也行不通,因为Excel需要在添加其他数据系列或重新排序数据时更改颜色。但我仍然希望有一种自动识别当前RGB值的方法。

一个丑陋的解决方法

对于条目数不超过6个的图表,一个简单的解决方法是利用主题颜色按顺序分配的事实,因此可以执行以下操作(例如):

chrt.SeriesCollection(1).DataLabels.Format.TextFrame2.TextRange.Font.Fill.ForeColor.ObjectThemeColor _
= msoThemeColorAccent1

据推测,这可以扩展到考虑在主题用尽后区分条目所使用的 TintAndShade ,但这样做太丑陋了。

研究

有人在这里提出了基本相同的问题(如何提取主题颜色),但没有得到解答。有几个来源建议将已知主题颜色转换为RGB值的方法(例如这里这里),但这只是说了一句废话;我并不知道颜色的先验知识,除了“这条线当前的颜色是什么”。


这是一个非常好的第一个问题。我记得线条图表在这方面特别难处理,因为我曾经在PPT中处理主题颜色(以及一些非主题颜色)的图表时遇到过类似的问题。我会看看是否有一个函数可以帮助你解决问题... - David Zemens
尝试调试,即使我分配 srs.Format.Line.ForeColor.ObjectThemeColor = msoThemeColorAccent2,然后尝试查询 ?srs.Format.Line.ForeColor.ObjectThemeColor,结果为 0(应该是6)。无论使用什么颜色,我都得到零。 - David Zemens
请查看这里的答案,看看是否能帮到您:https://dev59.com/Y3vaa4cB1Zd3GeqPB1fw - David Zemens
@DavidZemens 谢谢您的建议(以及友好的反馈!)。实际上,我在问题的结尾处链接了那个答案;问题是我不知道要尝试提取哪种主题颜色(或其变体)--除非利用我的知识,即它通过亮度变化循环显示6种调色板颜色,但我宁愿避免这样做。 - Alice
没错。就好像他们故意让ThemeColors难以使用一样。我看到了一个有趣的观察,我会将其作为“答案”添加,因为它太大了,无法放在评论中。 - David Zemens
4个回答

9

很有趣。我使用所有默认值创建了一条折线图,然后运行了这个过程:

enter image description here

Sub getLineCOlors()
Dim cht As Chart
Dim srs As Series
Dim colors As String
Dim pt As Point

Set cht = ActiveSheet.ChartObjects(1).Chart

For Each srs In cht.SeriesCollection
    With srs.Format.Line
    colors = colors & vbCrLf & srs.Name & " : " & _
            .ForeColor.RGB
    End With

Next

Debug.Print "Line Colors", colors

End Sub

即时窗口随即显示:
Line Colors   
Series1 : 16777215
Series2 : 16777215
Series3 : 16777215

但实际上情况并非如此。很明显它们都是不同的颜色。如果我使用.ObjectThemeColor而不是.RGB,那么我会得到全部为0的结果,这显然是错误的,通过观察图表可以证明!

Line Colors   
Series1 : 0
Series2 : 0
Series3 : 0

现在,有趣的事情来了:
如果我在创建图表后更改系列颜色(甚至通过分配相同的ThemeColors保持不变),那么该函数会显示有效的RGB值。
Line Colors   
Series1 : 5066944
Series2 : 12419407
Series3 : 5880731

似乎Excel(和PowerPoint/等)完全无法识别线图上自动分配的颜色。只有当您分配了颜色,它才能读取该颜色。
注意:线图非常挑剔,因为您没有填充,而是一个.Format.Line.ForeColor(和.BackColor),并且我IRC还有其他一些怪癖,比如您可以选择单个点并更改其填充颜色,然后这会影响前面线段的视觉外观等等...
这是否仅限于线图?也许吧。我的过去经验说“可能”,尽管我不能说这是一个错误,但它确实看起来像一个错误。
如果我在柱状图上运行类似的过程-再次仅使用自动分配的默认颜色,...
Sub getCOlumnColors()

Dim cht As Chart
Dim srs As Series
Dim colors As String
Dim pt As Point

Set cht = ActiveSheet.ChartObjects(2).Chart

For Each srs In cht.SeriesCollection

    With srs.Format.Fill
    colors = colors & vbCrLf & srs.Name & " : " & _
            .ForeColor.RGB
    End With

Next

Debug.Print "Column Colors", colors

End Sub

然后我得到了似乎是有效的RGB值:

Column Colors 
Series1 : 12419407
Series2 : 5066944
Series3 : 5880731

然而:它仍然不能识别一个有效的ObjectThemeColor。如果我更改.RGB,那么输出结果如下:

Column Colors 
Series1 : 0
Series2 : 0
Series3 : 0

基于这些观察结果,无法访问自动分配的颜色格式的ObjectThemeColor和/或.RGB属性显然存在一些问题。
正如Tim Williams所证实的那样,至少从2005年开始,与RGB相关的问题就是一个bug,而且很可能在Excel 2007+中也存在ObjectThemeColor等问题。不太可能很快解决,因此我们需要一个hack方案 :)
更新的解决方案:
将上述两种方法结合起来!将每个系列从线性转换为xlColumnClustered,然后从.Fill查询颜色属性,最后将系列图表类型更改回其原始状态。这可能比尝试利用顺序索引更可靠(如果用户重新排序系列,例如"Series1"位于索引3等,则顺序索引将根本不可靠)。
Sub getLineColors()
Dim cht As Chart
Dim chtType As Long
Dim srs As Series
Dim colors As String

Set cht = ActiveSheet.ChartObjects(1).Chart

For Each srs In cht.SeriesCollection
    chtType = srs.ChartType
    'Temporarily turn this in to a column chart:
    srs.ChartType = 51
    colors = colors & vbCrLf & srs.Name & " : " & _
            srs.Format.Fill.ForeColor.RGB
    'reset the chart type to its original state:
    srs.ChartType = chtType
Next

Debug.Print "Line Colors", colors

End Sub

1
从将近十年前的一个类似问题 - http://www.office-archive.com/33-excel/57ab74e17cab9710.htm - Tim Williams
1
谢谢Tim。如果Peltier和Walkenbach这么说,那肯定是个bug。只是很难相信它会持续十年甚至更长时间! - David Zemens
这是一个非常出色的解决方案。当我实施它时,图表类型会变成模板,并且右侧会保留第二个垂直轴。在最后将整个图表的图表类型改回线条类型即可解决这个问题。 - OpiesDad
1
太棒了!我不得不修改它以查看我的条形图中的每个点,因为这些条形是按值进行颜色编码的。不幸的是,它们是使用主题设置的,我无法找出颜色以制作匹配的图例。现在我已经有了它们,我将使用这个练习中的RGB值来设置一切。 - FreeMan

3
这是我最终使用的代码。
Sub ShowSeries()
Dim mySrs As Series
Dim myPts As Points
Dim chtType As Long
Dim colors As String

With ActiveSheet
    For Each mySrs In ActiveChart.SeriesCollection
        'Add label
        Set myPts = mySrs.Points
        myPts(myPts.Count).ApplyDataLabels ShowSeriesName:=True, ShowValue:=False

        'Color text label same as line color

        'if line has default color
        If mySrs.Border.ColorIndex = -4105 Then
            chtType = mySrs.ChartType
            'Temporarily turn this in to a column chart:
            mySrs.ChartType = 51
            mySrs.DataLabels.Format.TextFrame2.TextRange.Font.Fill.ForeColor.RGB = _
                mySrs.Format.Fill.ForeColor.RGB
            'reset the chart type to its original state:
            mySrs.ChartType = chtType

        'if line has a color manually changed by user
        Else
            mySrs.DataLabels.Font.ColorIndex = mySrs.Border.ColorIndex
        End If
    Next
End With

结束子例程


0

经过半天的努力,我终于解决了这个问题:

       Sub ......()

       Dim k as Integer
       Dim colorOfLine as Long

       ...............
       .................

       'Loop through each series
       For k = 1 To ActiveChart.SeriesCollection.Count

            With ActiveChart.FullSeriesCollection(k)

                .HasDataLabels = True

                'Put a fill on datalabels
                .DataLabels.Format.Fill.Solid

                'Get color of line of series
                colorOfLine = .Format.Line.ForeColor.RGB

                'Assign same color on Fill of datalabels of series
               .DataLabels.Format.Fill.ForeColor.RGB = colorOfLine

               'white fonts in datalabels
               .DataLabels.Format.TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(255, 255, 255)

            End With

        Next k
        ..........
        End Sub

0

在选择颜色时使用的输入实际上不是分别的R-G-B值,而似乎是以"vbLong"或类似"长整数"格式给出的预定义值。

例如: ActiveSheet.ChartObjects("Chart 1").Activate

RGBvalue = ActiveChart.FullSeriesCollection(1).Format.Line.ForeColor.RGB

Debug.Print "RGB value = " & RGBvalue

同样,您可以像这样用RGB值获取指定颜色的输入值: RGBvalue = RGB(R, G, B)

要更改线条的颜色,则可以将输入值作为1)或2)给出:

1) ActiveChart.FullSeriesCollection(1).Format.Line.ForeColor.RGB = RGBvalue

2) ActiveChart.FullSeriesCollection(1).Format.Line.ForeColor.RGB = RGB(R, G, B)

否则,如果您想特别获取RGB值,则此处有代码可以实现该功能:

https://www.thespreadsheetguru.com/vba/2014/11/5/retrieve-excel-cells-font-fill-rgb-color-code

十六进制代码也可以很容易地通过VBA函数获得:hex(RGBvalue)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接