背景色の範囲を変える

先日の、行全体が塗りつぶされているExcelシートを指定した範囲だけの塗りつぶしに変える - プログラミングお勉強記録
をコードレビューしてもらい、かなり大幅に変更しました。

まずはコードレビュー後のコード↓

Option Explicit

Sub 背景色範囲変更()

'-----仕様-----
'行全体の背景色を設定しているところを、指定した範囲だけの設定に変える

Dim columnColoredArea As Integer
columnColoredArea = InputBox("何列分の色を変えますか?例:A列までは「1」、J列までは「10」", "入力してください")

Dim i As Integer
For i = 2 To Range("A65536").End(xlUp).Row
    With Cells(i, 1)                               '(i行め, A列)
        If Not .Interior.Color = xlNone Then       '「背景色なし」では“なかったら”、つまり背景色の設定があったら
            Dim primaryCellColor          
            primaryCellColor = .Interior.Color     '(i行め, A列)の色を変数名 primaryCellColor に格納
            Rows(i).Interior.Color = xlNone        '行全体の背景色を「なし」に設定
            Range(Cells(i, 1), Cells(i, columnColoredArea)).Interior.Color = primaryCellColor          ' (i行め, A列)の色を、A列から入力した列数分までの背景色に設定する
        End If
    End With
Next i
End Sub

変更箇所まとめ

変数名 columnColoredArea

最初、column_colored_area としていましたが、これは「スネークケース」というそうです。
(アンダースコアがついているので、字面がにょろにょろしている)

これに対し、ExcelVBA では「キャメルケース」の場合が多いそうなので、
そちらに統一することにしました。

column_colored_area
columnColoredArea

くらべてなるほど。
どちらが間違いとかではなくて、統一されていれば、見やすいという話。

背景色をA列の色から取得する

最初、背景色は2色で定義していたのですが、これは今回のシートの場合であって、

たとえば3色の設定があったりとか、
黄色とか以外の色が設定されていたりとか、

他の場合でも対応できる仕様になりました。
それぞれの行にコメントいれてあります。

エラー処理をいれる

コードはかなりすっきり、汎用性も高まったのですが、
インプットボックス部分のエラー処理として、
・「キャンセル」をクリックした場合
・数字以外を入力した場合
・空のまま「OK」を押した場合
の処理を書き加えなくてはなりません。

これがむずかしかった…

ExcelVBA の InputBox 関数の仕様をよく調べないといけません。

「キャンセル」をクリックした場合

ユーザーが「キャンセル」をクリックすると、
InputBox 関数の帰り値は vbNullString になります。
いったん StrPtr() でキャスト(型変換)をして、
一致すれば「キャンセルされました」というメッセージとともにマクロを抜けます。

ブログなどを見ていると、キャンセル処理は

If inputValue = "" Then
End Sub
End If

と書かれていることが多いのですが、これをやるとエラーメッセージが出てきます。

また StrPtr() しないと、「空のままOKを押したとき」と同じと判断され、この次の処理に該当して、
「数値を入力してください」というメッセージが出て矛盾してしまいます。

奥が深い・・・

数字以外を入力した場合、空のまま「OK」を押した場合

この場合は「数値を入力してください」というメッセージを出したいので、
inputValue が数字かどうか(IsNumeric)、あるいは空かどうか(IsEmpty)を判定して、
そうじゃなかった場合、メッセージが出て、マクロから抜けます。

型を一致させる

InputBox で入力してもらった値を判定のために String にして扱っていましたが、
あとでこの値は Cells プロパティで扱いたいので、
Integer に変換します。(String でなければ Variant とかでも大丈夫だった)

出来上がり!!

Option Explicit

Sub 背景色範囲変更()

'----------仕様-------------------------------------------------------
'背景色が行全体に設定されているところを、入力した列数分の設定に変える
'背景色はA列を起点として、入力された列数分だけ設定される
'(たとえば「5」と入力すれば、A列からE列までの設定になる)
'色は設定されていた色をそのまま使用する
'(黄色く塗られている行は黄色、青く塗られている行は青)
'---------------------------------------------------------------------

Dim inputValue As Variant
inputValue = InputBox("何列分の色を変えますか?「1」以上の数字を入力してください。例:A列までは「1」、J列までは「10」", "入力してください")

'validation
'キャンセルが押された場合は inputValue が vbNullString を返すので StrPtr() でキャストして比較するとよい
If StrPtr(inputValue) = 0 Then
    MsgBox ("キャンセルされました")
    Exit Sub
'数字以外と入力したときと、空のままOKを押したとき
ElseIf Not IsNumeric(inputValue) Or IsEmpty(inputValue) Then
    MsgBox ("数値を入力してください")
    Exit Sub
End If

Dim columnColoredArea As Integer
columnColoredArea = CInt(inputValue)

Dim i As Integer
For i = 2 To Range("A65536").End(xlUp).Row
    With Cells(i, 1)                               '(i行め, A列)
        If Not .Interior.Color = xlNone Then       '「背景色なし」では“なかったら”、つまり背景色の設定があったら
            Dim primaryCellColor          
            primaryCellColor = .Interior.Color     '(i行め, A列)の色を変数名 primaryCellColor に格納
            Rows(i).Interior.Color = xlNone        '行全体の背景色を「なし」に設定
            Range(Cells(i, 1), Cells(i, columnColoredArea)).Interior.Color = primaryCellColor          ' (i行め, A列)の色を、A列から入力した列数分までの背景色に設定する
        End If
    End With
Next i
End Sub

データ型の変換

今回、エラー処理をするにあたってデータ型についてはじめてちゃんと意識しました。
エラーメッセージ「型が一致しない」と言われたら、
変換すればいいんですね。

参考URL
VBA基本(データの型変換)

先生からのコメント

基本仕様をみて、どんな処理かわかるようにするといい

最初に仕様コメントをいれるときに、
たとえばその下のコードを読まなくても、
どんな処理が行われるのかわかるように書いておくといい、とのこと。

ちなみに

今気づいたけど、「0」を入れちゃった場合の処理を書いてなかった。
初めに「1」以上の数字を入力してくださいって出してるけど…