前回の記事では「右クリックメニューの追加」を紹介しましたが、今回はそのメニューに「書式の設定」を実装します。フォントと罫線の変更になりますが、難しいコードは出てきません。Withステートメントという命令文が出てきますが、これの雰囲気を掴んでもらえれば今回のお題はクリアです。
覚える用語
- Withステートメント
VBAで頻繁に使用する命令文です。
- オブジェクト、プロパティ
用語だけ覚えて下さい。意味はわからなくても問題ありません。
Withステートメントで右クリックメニューに「書式を変更するメニュー」を追加
サブメニューに「書式の設定」を実装する
仕様は以下の通りです。
- 実行する内容は「書式を太字,赤色,赤色の下罫線(中太線)にする」
- 実行内容を解除(キャンセル)するメニューも作る
前回のサブメニューで書式の設定と書式の解除を実行できるようにします。「VBA 書式設定」で検索してもいまいちだったので「VBA フォント」で探しました。
多分に漏れず、サンプルを頂戴します(ありがとうございます)。VBEを起動、標準モジュール を挿入、myMacroを書き換えます。
Sub 書式変更オン() 'マクロ名
With Range("A1").Font 'A1セルのフォントを取得
.Name = "MS明朝" 'フォントの種類を変更
.Bold = True '太字に変更
.Color = vbRed '赤色に変更
.FontStyle = "斜体" '斜体に変更
.OutlineFont = True 'これは無視して下さい
.Size = 16 'サイズを16に変更
End With
End Sub
Range(“A1”).FontでA1セルのフォントを指定しているっぽいですね。とりあえず適当に動かして確認してみましょう。あらかじめA1セルに何かを入力しておきます。
Alt+F8でマクロ書式変更オンを実行すると、A1セルのフォントが変更されました。
先ほどのサイトに罫線の変更もサンプルがあったので引き続き改造してみます。
- フォントを太字と赤色の変更のみ残し、他は削除
- 罫線を赤色と中太線に変更
Sub 書式変更オン()
With Range("A1").Font 'A1セルのフォントを取得
.Bold = True '太字に変更
.Color = vbRed '赤色に変更
End With
With Range("A1").Borders(xlEdgeBottom) 'A1セルの罫線を取得
.Color = vbRed '赤色に変更
.Weight = xlMedium '中太線に変更
End With
End Sub
マクロ書式変更オンを実行すると、A1セルのフォント変更に加え、下罫線も追加されました。
もう一つのサブメニューに「書式の解除」を実装する
もう一つのサブメニューボタンで書式の解除を実行できるようにします。これは元に戻すだけなのでコードはサンプルのmyMacroがそのまま流用できそうです。
Sub 書式変更OFF()
With Range("A1").Font 'A1セルのフォントを取得
.Bold = False '太字を解除
.Color = vbBlack '黒色に変更
End With
Range("A1").Borders(xlEdgeBottom).LineStyle = xlLineStyleNone '罫線を消す
End Sub
6行目のコードがmyMacroと若干変わっています。罫線を元の状態に戻すという事は「消す」事になります。ググるとLineStyle = xlLineStyleNoneで消せる事がわかりました。
ググりついでに書式をクリアできる事もわかりました。Range(“A1”).ClearFormatsでフォント含めて全ての書式設定がクリアできるので便利と思ったのですが、フォントの種類やサイズもクリアされてしまいます。都合が悪いので、今回はフォントと罫線、それぞれ項目を指定して変更することにします。
この辺は仕様とにらめっこしながら適切なコードを使用する必要があります。
マクロ書式変更OFFを実行すると、A1セルのフォントが元の状態に戻りました。
選択したセルでマクロを実行する
このままではA1セルしか変更できないので、選択したセルでマクロが実行できるようにします。「VBA セルの選択」で検索します。…が、検索上位を読んでみてもピンとこないですね。
ただ読んでみて何となくわかったのですが、いま求めている事は「セルを選択する」事ではなく、「選択されたセル」をどうにかしたい訳です。今度は「VBA 選択したセル」で検索します。
おっと、お目当てのサイトが見つかったようです。
Selectionプロパティを使えと書いてあります。Range(“A1”)をSelectionに置き換えたら動きそうな気配(適当)。やってみましょう。
Sub 書式変更オン()
With Selection.Font
.Bold = True
.Color = vbRed
End With
With Selection.Borders(xlEdgeBottom)
.Color = vbRed
.Weight = xlMedium
End With
End Sub
Sub 書式変更オフ()
With Selection.Font
.Bold = False
.Color = vbBlack
End With
Selection.Borders(xlEdgeBottom).LineStyle = xlLineStyleNone
End Sub
適当なセルに何か入力し、そこを選択した状態で右クリックから書式変更ONを選択すると、書式が設定されました。同じく書式変更OFFを選択すると書式が解除されました。が…
できました。と言いたいところですが不十分でした。複数範囲を選択した時、罫線の設定が範囲の一番下しか変更されません。そりゃそうですよね、下罫線ですから。
つまり中罫線も設定してやれば解決するのではないでしょうか?
Sub 書式変更オン()
With Selection.Font
.Bold = True
.Color = vbRed
End With
With Selection.Borders(xlEdgeBottom)
.Color = vbRed
.Weight = xlMedium
End With
With Selection.Borders(xlInsideHorizontal) '選択したセルの中罫線を取得
.Color = vbRed
.Weight = xlMedium
End With
End Sub
Sub 書式変更オフ()
With Selection.Font
.Bold = False
.Color = vbBlack
End With
With Selection
.Borders(xlEdgeBottom).LineStyle = xlLineStyleNone
.Borders(xlInsideHorizontal).LineStyle = xlLineStyleNone '選択したセルの中罫線を消す
End With
End Sub
複数範囲を選択しても、全てのセルで下罫線が設定、解除できました。セルを一つしか選択していない状態でも問題ありません(中罫線でエラーになる事はない) 。
これで希望通りの動きになりました。ちなみに21行目から24行目にWithステートメントを使ってみました。これ、要は同じコードを何回も書かなくていい仕組みです。
Withステートメント
構文
Officeリファレンスからの引用です。
With object
[ statements ]
End With
With ステートメントを使用すると、特定のオブジェクトに対してオブジェクト名の修飾を繰り返すことなく一連のステートメントを実行できます。 たとえば、1 つのオブジェクトにある複数の異なる プロパティを変更する場合は、With 制御構造の内側にプロパティの割り当てステートメントを配置してオブジェクトを 1 回参照します。これにより、プロパティの割り当てごとにオブジェクトを参照する必要がなくなります。
https://docs.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/with-statement
意味分かりませんよね。ヘルプ読んでこんなの出てきたらやる気削がれます。ただ、その内ここに書かれていることが理解できるようになるはずです。
22,23行目でざっくり説明します。当該部をWithステートメントなしで記述するとこうなります。
Selection.Borders(xlEdgeBottom).LineStyle = xlLineStyleNone
Selection.Borders(xlInsideHorizontal).LineStyle = xlLineStyleNone
リファレンス引用部のオブジェクトとはコード上のSelectionにあたります。プロパティ がBorders(xlEdgeBottom).LineStyleとBorders(xlInsideHorizontal).LineStyleです。
「1つのオブジェクトにある複数の異なるプロパティ」とは「 Selectionにある Borders(xlEdgeBottom).LineStyleとBorders(xlInsideHorizontal).LineStyle」と置き換えることができます。
引用に戻って要約すると、「Withで1回Selectionを参照したら、Borders(xlEdgeBottom).LineStyleとBorders(xlInsideHorizontal).LineStyleは先頭にSelectionを記述しなくてもいい」となります。
With Selection 'Withでオブジェクトを参照したら
.Borders(xlEdgeBottom).LineStyle = xlLineStyleNone 'プロパティの先頭にオブジェクトを記述しなくてもいい
.Borders(xlInsideHorizontal).LineStyle = xlLineStyleNone
End With
おさらいで全てのプロシージャでWithステートメントなしで記述してみます。
Sub 書式変更オン()
Selection.Font.Bold = True
Selection.Font.Color = vbRed
Selection.Borders(xlEdgeBottom).Color = vbRed
Selection.Borders(xlEdgeBottom).Weight = xlMedium
Selection.Borders(xlInsideHorizontal).Color = vbRed
Selection.Borders(xlInsideHorizontal).Weight = xlMedium
End Sub
Sub 書式変更オフ()
Selection.Font.Bold = False
Selection.Font.Color = vbBlack
Selection.Borders(xlEdgeBottom).LineStyle = xlLineStyleNone
Selection.Borders(xlInsideHorizontal).LineStyle = xlLineStyleNone
End Sub
Withステートメントを使ったコードと比較してもらえれば、どちらが読みやすいか分かると思います。日本語で、文脈的に主語がわかりきっているのに何回も主語を言われたら冗長ですよね?それと同じでプログラムもわかりきっている事は省略できます。
右クリックメニューに実装する
いよいよ実装です。前回のコードと今回のコードを組み合わせます。マクロ名とメニュー名は書き換えます。
Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
On Error Resume Next
CommandBars("Cell").Controls("書式変更").Delete
With CommandBars("Cell").Controls.Add(Before:=1, Type:=msoControlPopup)
.Caption = "書式変更"
With .Controls.Add
.Caption = "ON"
.OnAction = "書式変更ON" 'subプロシージャの[書式変更ON]を実行する
End With
With .Controls.Add
.Caption = "OFF"
.OnAction = "書式変更OFF" 'subプロシージャの[書式変更OFF]を実行する
End With
End With
End Sub
Private Sub Worksheet_Deactivate()
On Error Resume Next
CommandBars("Cell").Controls("書式変更").Delete
End Sub
Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
On Error Resume Next
CommandBars("Cell").Controls("書式変更").Delete
With CommandBars("Cell").Controls.Add(Before:=1, Type:=msoControlPopup)
.Caption = "書式変更"
With .Controls.Add
.Caption = "ON"
.OnAction = "書式変更ON" 'subプロシージャの[書式変更ON]を実行する
End With
With .Controls.Add
.Caption = "OFF"
.OnAction = "書式変更OFF" 'subプロシージャの[書式変更OFF]を実行する
End With
End With
End Sub
Private Sub Worksheet_Deactivate()
On Error Resume Next
CommandBars("Cell").Controls("書式変更").Delete
End Sub
Sub 書式変更オン()
With Selection.Font
.Bold = True
.Color = vbRed
End With
With Selection.Borders(xlEdgeBottom)
.Color = vbRed
.Weight = xlMedium
End With
With Selection.Borders(xlInsideHorizontal)
.Color = vbRed
.Weight = xlMedium
End With
End Sub
Sub 書式変更オフ()
With Selection.Font
.Bold = False
.Color = vbBlack
End With
With Selection
.Borders(xlEdgeBottom).LineStyle = xlLineStyleNone
.Borders(xlInsideHorizontal).LineStyle = xlLineStyleNone
End With
End Sub
今回もほとんど知識なしでサンプルいじって完成です。「動けばいい」の精神でサンプルから少しずつ知識を吸収していけば、その内自分でマクロを作れるようになります。焦らずにたくさんのサンプルに触れましょう。
おさらい
With [オブジェクト]と記述することでEnd Withまでの間、[オブジェクト]の記述を省略できます。
- 同じ記述を繰り返さなくていいので入力が省力化できる
- 可読性(読みやすさ)が上がる