24bitカラーをRGBに分解する

# はじめに

VBAで色を表す際は、多くの場合32bit整数である`Long`型で表現される。
RGBの値が決まっていれば`VBA.RGB`関数で色を作成することが出来るが、その逆の色の数字からRGBを取得する方法は用意されていない。

そこで自分の勉強も兼ねて、色の変換を行うクラスを作成してみた。

# コード

```vbnet
Option Explicit

'色からRGBを取得しやすくするためのクラス
'プロパティ
    'Color      :読み書き:Long   :Long型の色
    'HexColor   :読み    :String :Colorの16進数表示
    'Red        :読み書き:Byte   :ColorのR部分
    'Green      :読み書き:Byte   :ColorのG部分
    'Blue       :読み書き:Byte   :ColorのB部分

'メソッド
    'なし

Private clsColor As Long
Private clsRed As Byte
Private clsGreen As Byte
Private clsBlue As Byte

Private Sub ChangeColor(iColor As Long)
    Select Case iColor
        Case 0 To &HFFFFFF  'RGB(0, 0, 0) To RGB(255, 255, 255)
            'Next
        Case Else
            Call Err.Raise(vbObjectError, VBA.TypeName(Me), "0 から 16777215 の間で指定してください")
    End Select
    
    Let clsColor = iColor
    
    Dim tmpColor As Long
    tmpColor = iColor
    Const DIV& = 256
    
    Let clsRed = tmpColor Mod DIV
    tmpColor = (tmpColor - clsRed) / DIV
    
    Let clsGreen = tmpColor Mod DIV
    tmpColor = (tmpColor - clsGreen) / DIV
    
    Let clsBlue = tmpColor Mod DIV
    
End Sub


Public Property Get Color() As Long
    Let Color = clsColor
End Property

Public Property Let Color(ByVal SetColor As Long)
    Call ChangeColor(SetColor)
End Property


Public Property Get HexColor() As String
    Let HexColor = VBA.Hex$(clsColor)
End Property


Public Property Get Red() As Byte
    Let Red = clsRed
End Property

Public Property Let Red(ByVal iRed As Byte)
    Call ChangeColor(VBA.RGB(VBA.CInt(iRed), VBA.CInt(clsGreen), VBA.CInt(clsBlue)))
End Property


Public Property Get Green() As Byte
    Let Green = clsGreen
End Property

Public Property Let Green(ByVal iGreen As Byte)
    Call ChangeColor(VBA.RGB(VBA.CInt(clsRed), VBA.CInt(iGreen), VBA.CInt(clsBlue)))
End Property


Public Property Get Blue() As Byte
    Let Blue = clsBlue
End Property

Public Property Let Blue(ByVal iBlue As Byte)
    Call ChangeColor(VBA.RGB(VBA.CInt(clsRed), VBA.CInt(clsGreen), VBA.CInt(iBlue)))
End Property
```

## 簡易確認用

上記のクラスを`RGBColor`という名前で作成してください。

```vbnet
Sub RGBColorTest_Tekitou()
    Dim myCls As RGBColor
    Set myCls = New RGBColor
    
    With myCls
        Debug.Assert .Color = RGB(0, 0, 0)
        
        .Color = RGB(255, 255, 255)
        Debug.Assert .Color = RGB(255, 255, 255)
        Debug.Assert .Red = 255
        Debug.Assert .Green = 255
        Debug.Assert .Blue = 255
        Debug.Assert .HexColor = "FFFFFF"
        
        .Blue = 0
        Debug.Assert .Color = RGB(255, 255, 0)
        Debug.Assert .Red = 255
        Debug.Assert .Green = 255
        Debug.Assert .Blue = 0
        Debug.Assert .HexColor = "FFFF"
        
        .Green = 128
        Debug.Assert .Color = RGB(255, 128, 0)
        Debug.Assert .Red = 255
        Debug.Assert .Green = 128
        Debug.Assert .Blue = 0
        Debug.Assert .HexColor = "80FF"
        
        On Error Resume Next
            .Color = VBA.RGB(255, 255, 255) + 1
            Debug.Assert Err.Number <> 0
        On Error GoTo 0
    End With
    Stop
End Sub
```

# 作成にあたって

当初は色をを16進数表記変換にして、文字列演算でごり押す方法だった。
途中で256で割れば良いことに気付き、現在の形になった。

RGBの値を算出するタイミングとして、

1. RGB参照時に計算を行う
2. 色設定時にRGBをまとめて算出する

で迷ったが、フラグ管理が面倒だったため2の方法をとることにした。
また、内部変数の`cls~`を直接いじるのを`ChangeColor`プロシージャにまとめることで、ロジック部分を集約できた。