从Range.Interior.Color(或任何其他颜色属性)返回RGB值

26

我想逐步将一个单元格的背景颜色改为黑色,但是发现 Range.Interior.Color 方法返回的是一个似乎随意的 Long 类型数值。在 MSDN 的文档中几乎没有关于这个数值代表什么的信息。请问有没有一种方法可以从这个长整型数值中获取 RGB 值呢?实际上,我需要 RGB(red, green, blue) 函数的相反操作。

8个回答

52

那个“任意”的数字是RGB值的数学组合(B256^2 + G256 + R),以及十六进制颜色值转换为十进制数(从16进制到10进制),这取决于您希望如何看待它。只是不同的进制而已。以下是我在为Excel编写的XLAM插件文件中使用的方法。这种方法已经非常有用了。我已经在我的插件文件中包含了文档。

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'   Function            Color
'   Purpose             Determine the Background Color Of a Cell
'   @Param rng          Range to Determine Background Color of
'   @Param formatType   Default Value = 0
'                       0   Integer
'                       1   Hex
'                       2   RGB
'                       3   Excel Color Index
'   Usage               Color(A1)      -->   9507341
'                       Color(A1, 0)   -->   9507341
'                       Color(A1, 1)   -->   91120D
'                       Color(A1, 2)   -->   13, 18, 145
'                       Color(A1, 3)   -->   6
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function Color(rng As Range, Optional formatType As Integer = 0)     As Variant
    Dim colorVal As Variant
    colorVal = rng.Cells(1, 1).Interior.Color
    Select Case formatType
        Case 1
            Color = WorksheetFunction.Dec2Hex(colorVal, 6)
        Case 2
            Color = (colorVal Mod 256) & ", " & ((colorVal \ 256) Mod 256) & ", " & (colorVal \ 65536)
        Case 3
            Color = rng.Cells(1, 1).Interior.ColorIndex
        Case Else
            Color = colorVal
    End Select
End Function

2
如果RGB()数字被编码为R*256^2 + G*256 + B,那么这就不是VBA了,因为在VBA中,最简单的事情必须是古怪的。实际上恰恰相反:B*256^2 + G*256 + R - Nickolay
是的。我之所以注意到这一点,是因为我认为手动计算会比复制粘贴您(正确的)代码并运行它更快:) - Nickolay
1
@Nickolay,就我所知,这种奇怪的问题是出现在Excel对象模型(类型库)上,而不是VBA(语言)上。 Excel v1.0已经需要与1985年的工作表向后兼容,而且我认为Excel工作表单元格内部的功能比CSS诞生的时间早得多。说到稀奇古怪的事情... - Mathieu Guindon
@Mathieu:嘿,顺便说一下,感谢你对Rubberduck所做的努力! - Nickolay
@Nickolay,代表开发团队的每个人,感谢您!请在GitHub上给我们点赞!=) - Mathieu Guindon
显示剩余4条评论

29

很高兴看到Wyatt先生使用了快速的颜色转RGB方法。

R = C Mod 256
G = C \ 256 Mod 256
B = C \ 65536 Mod 256

比起一些人推荐使用的左中右十六进制字符串,它要快很多倍。


17

简短回答:

没有内置的功能可以实现这个需求,你需要编写自己的函数。

详细回答:

从 Interior.Color 属性返回的长整型是典型十六进制颜色转换为十进制的结果,例如在 HTML 中我们习惯看到的 "66FF66"。此外,常量 xlNone (-4142) 可以传递来将单元格设置为无背景颜色,不过这样的单元格会标记成白色 RGB(255, 255, 255)Get 属性中获得。了解了这些,我们就可以编写一个函数来返回一个或多个合适的 RGB 值。

幸运的是,Allan Wyatt 先生已经在这里为我们准备好了这样的函数!

确定颜色的 RGB 值


8
其他答案对我没有用。我发现以下内容可以解决问题:
R = C And 255
G = C \ 256 And 255
B = C \ 256 ^ 2 And 255

并且它正常工作。


你和Harry的代码都能正常工作。例如,RGB(50,100,200)的红色值可以通过 RGB(50,100,200) Mod 256 或 RGB(50,100,200) And 255 来获取。 - Mill
我怀疑它能够工作是因为你处于一个特殊情况下,其中 X Mod 256X And 255 是相同的。通过执行 And 255,实际上你过滤了所有从 256 开始的位,并且只保留了前8位,这正好是256的大小。对于128、64等也是同样的道理。 - Ama

3

这是另一种解决问题的方法

'
' Type definition in declarations
'
Type RGBcolor
    r As Long
    g As Long
    b As Long
End Type
'
' Inverse RGB function
'
Function GetRGB(ByVal x As Long) As RGBcolor
    With GetRGB
        .r = x Mod 256
        x = x \ 256
        .g = x Mod 256
        x = x \ 256
        .b = x Mod 256
    End With
End Function
'
'  Sub to test the GetRGB function
'
Sub test(x As Long)
Dim c As RGBcolor
c = GetRGB(x) ' returns RGB values: c.r, c.g, c.b
Debug.Print "Original", "Red", "Green", "Blue", "Recombined value"
Debug.Print x, c.r, c.g, c.b, RGB(c.r, c.g, c.b)
End Sub
'
'
***** IMMEDIATE WINDOW *****
test 1000
Original      Red           Green         Blue          Recombined value
 1000          232           3             0             1000 

2

简短回答

将这三个自解释的一行程序放入一个模块中,然后在VBA或工作表公式中使用它们:

Function rr(rgbCode): rr = rgbCode Mod 256: End Function
Function g(rgbCode): g = (rgbCode \ 256) Mod 256: End Function
Function b(rgbCode): b = rgbCode \ 65536: End Function

(我无法在红色函数名称中使用单个R,因为它已被保留用于Goto F5Name CTRL+F3对话框。)


1
请注意,对于十六进制值,如果您导出到HTML,您也会得到一些小问题。
最好从各个颜色创建十六进制字符串,而不是从ColorVal数字返回十六进制。
原因是,如果单元格是“纯”颜色(如绿色/蓝色),则可能会得到一些无效的十六进制数字。
红色 - RGB(255,0,0)返回“FF” - 应返回“FF0000”
蓝色 - RGB(0,0,255)返回“FF00000” - 应返回“0000FF”
{{link1:在此输入图像描述}}
如果您使用这些来创建HTML / CSS颜色输出,则会为任何蓝色单元格获取红色。
我修改了脚本以根据RGB值组装每个两个字符的十六进制“块”,并使用UDF填充前导0,其中输出一个字符的情况下返回(希望如果您正在阅读此内容,您可以创建类似的东西)。
Color = ZeroPad(Hex((colorVal Mod 256)), 2) & ZeroPad(Hex(((colorVal \ 256) Mod 256)), 2) & ZeroPad(Hex((colorVal \ 65536)), 2)

--编辑:忘记包含UDF的代码了...
Function ZeroPad(text As String, Cnt As Integer) As String
'Text is the string to pad
'Cnt is the length to pad to, for example  ZeroPad(12,3) would return a string '012' , Zeropad(12,8) would return '00000012' etc..
Dim StrLen As Integer, StrtString As String, Padded As String, LP As Integer


StrLen = Len(Trim(text))


    If StrLen < Cnt Then

        For LP = 1 To Cnt - StrLen

            Padded = Padded & "0"

        Next LP

    End If

ZeroPad = Padded & Trim(text)

ENDOF:


End Function

顺便说一句 - 如果您想要在表单编辑器中显示十六进制代码(与普通的HTML十六进制颜色不同),则需要使用特定格式。

    Case 4  ' ::: VBA FORM HEX :::
    Color = "&H00" & ZeroPad(Hex((colorVal \ 65536)), 2) &  ZeroPad(Hex(((colorVal \ 256) Mod 256)), 2) & ZeroPad(Hex((colorVal Mod 256)), 2) & "&"

+1 我认为您正在详细阐述我的答案下注释中所指出的内容(即Excel中十六进制部分与HTML实现相反,并添加前导零)。此外,后者可以不使用新函数来完成。工作表函数转换为十六进制具有第二个参数用于长度。因此:WorksheetFunction.Dec2Hex(colorVal Mod 256, 2) & WorksheetFunction.Dec2Hex((colorVal \ 256) Mod 256, 2) & WorksheetFunction.Dec2Hex(colorVal \ 65536, 2) 是您的第一个,而 WorksheetFunction.Dec2Hex(colorVal, 6) 是您的第二个。 - Mark Balhoff

0

Mark Balhoff的VBA脚本很好用。所有的功劳归于他。

如果您想要获取有条件格式的单元格的颜色代码/索引,可以像这样修改代码:

'----------------------------------------------------------------
'   Function            Color
'   Purpose             Determine the Background Color Of a Cell
'   @Param rng          Range to Determine Background Color of
'   @Param formatType   Default Value = 0
'                       0   Integer             color of cell, not considering conditional formatting color
'                       1   Hex                 color of cell, not considering conditional formatting color
'                       2   RGB                 color of cell, not considering conditional formatting color
'                       3   Excel Color Index   color of cell, not considering conditional formatting color
'                       4   Integer             "real" visible color of cell (as the case may be the conditional formatting color)
'                       5   Hex                 "real" visible color of cell (as the case may be the conditional formatting color)
'                       6   RGB                 "real" visible color of cell (as the case may be the conditional formatting color)
'                       7   Excel Color Index   "real" visible color of cell (as the case may be the conditional formatting color)
'   Usage               Color(A1)      -->   9507341
'                       Color(A1, 0)   -->   9507341
'                       Color(A1, 1)   -->   91120D
'                       Color(A1, 2)   -->   13, 18, 145
'                       Color(A1, 3)   -->   6
'-----------------------------------------------------------------
Function Color(rng As Range, Optional formatType As Integer = 0) As Variant
    Dim colorVal As Variant
    Select Case formatType
        Case 0 To 3
            colorVal = Cells(rng.Row, rng.Column).Interior.Color
        Case 4 To 7
            colorVal = Cells(rng.Row, rng.Column).DisplayFormat.Interior.Color
    End Select
    Select Case formatType
        Case 0
            Color = colorVal
        Case 1
            Color = Hex(colorVal)
        Case 2
            Color = (colorVal Mod 256) & ", " & ((colorVal \ 256) Mod 256) & ", " & (colorVal \ 65536)
        Case 3
            Color = Cells(rng.Row, rng.Column).Interior.ColorIndex
        Case 4
            Color = colorVal
        Case 5
            Color = Hex(colorVal)
        Case 6
            Color = (colorVal Mod 256) & ", " & ((colorVal \ 256) Mod 256) & ", " & (colorVal \ 65536)
        Case 7
            Color = Cells(rng.Row, rng.Column).DisplayFormat.Interior.ColorIndex
    End Select
End Function

1
一个有价值的补充,我很感激引用,但是有几个快速注意事项:1) 如果将其用作工作表函数,则DisplayFormat调用会出错;2) 将第二个Select Case formatType更改为Select Case formatType Mod 4可以删除4到7个案例(不必要的代码重复)。我还可能选择将大开关块中的最后一个Case转换为Case Else以默认处理错误的用户输入,并将较小的开关块转换为If formatType < 4 Then ... Else ... End If,但这两个是更个人化的选择。 - Mark Balhoff

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