VBAに全く触れたことのない人、マクロとは何ぞ?な人向けの記事です。最後まで読めばとりあえずマクロとVBAの雰囲気は掴めます。操作方法含めて紹介するのでまずは触れてみて下さい。もちろん、右クリックメニューを追加するマクロの実装もできます。

本記事はVBAに触れたことが無い人向けの記事になっています。右クリックメニューの追加ができるVBAコードだけが欲しい人は下の記事がおすすめです。

覚える用語は3つだけ
- マクロ
エクセルの操作を自動化する機能です。
- VBA
Visual Basic for Applicationsの略で、マクロに使われるプログラム言語です。
- VBE
Visual Basic Edtorの略で、VBAコードを記述するソフトです。

今すぐ覚えなくてもOKです。この記事を読み終えた頃には覚えている筈です。
準備

開発タブでVisual BasicアイコンをクリックするとVBE(VisualBasicEditor)が表示されます
ショートカットはAlt+F11です。今後マクロに本気で取り組むのであれば、覚えておいた方が吉です。

表示されたソフトがVisualBasicEditorです。ここにコードを記述してマクロを作成します。
右クリックメニューが追加されたサンプルを動かしてみる
サンプルを入手する
まずはWeb上で適当なサンプルを入手しましょう。適切なワードでググれば、ほとんどの場合目的のサンプルが見つかります。今回は「VBA 右クリックメニュー 追加」で検索します。
検索上位を読むとどうやら、CommandBarsプロパティを使用してCommandBarオブジェクトを参照する事でメニューを追加できるようです。
うん、意味はよく分かりません。ただ参考になりそうなコードがあるのでコピペでいただきましょう。

挿入されたModule1をダブルクリックし、右側のコードウィンドウへコピペする。
Sub Sample1() 'マクロ名
With CommandBars("Cell").Controls.Add(Type:=msoControlButton) '右クリックメニューを追加
.Caption = "Button" '追加するメニューの名前
.OnAction = "myMacro" 'メニューを押した時に実行されるマクロ名
End With
End Sub
Sub myMacro() 'マクロ名
MsgBox "Hello" 'メッセージボックスに「Hello」と表示される
End Sub
Sub Sample2() 'マクロ名
CommandBars("Cell").Controls("Button").Delete '追加したメニューを削除する
End Sub

‘の後に続く文字はマクロ実行時には無視されます。コメントとして利用するのが一般的です。説明、備忘と用途は多岐に渡ります。不要なら付与する必要はありません。
1~6行目、8~10行目、12~14行目がそれぞれSub~End Subのコードで括(くく)られています。この括りをプロシージャといいます。VBAには単位があり、構成は次の通りです。
- 1行ごと…ステートメント
- Sub~End Subで括られたステートメントの集まり…プロシージャ
- プロシージャの集まり…モジュール
- モジュールの集まり…プロジェクト
サンプルで構成を確認してみます。
'///////モジュール///////
'*******プロシージャ始まり*******
Sub Sample1() 'ステートメント
With CommandBars("Cell").Controls.Add(Type:=msoControlButton) 'ステートメント
.Caption = "Button" 'ステートメント
.OnAction = "myMacro" 'ステートメント
End With 'ステートメント
End Sub 'ステートメント
'*******プロシージャ終わり*******
'*******プロシージャ始まり*******
Sub myMacro() 'ステートメント
MsgBox "Hello" 'ステートメント
End Sub 'ステートメント
'*******プロシージャ終わり*******
'*******プロシージャ始まり*******
Sub Sample2() 'ステートメント
CommandBars("Cell").Controls("Button").Delete 'ステートメント
End Sub 'ステートメント
'*******プロシージャ終わり*******

用語を今覚える必要はありません。Sub~End Subが一括りである事が理解できればOKです。
VBEの画面を閉じ(右上の×を押せば閉じます)、早速コピペしたコードを実行してみましょう。
VBEに記述したコードは、エクセルのファイルと一緒に保存されるのでここで保存しなくても消える事はありません。が、マクロ作成中は不測の事態が起きやすいのでまめに保存しておいた方がいいかも知れません。気になる人はVBE画面にも保存アイコンがあるのでそこを押して保存して下さい。
サンプルを実行して動きを確認する

開発タブのマクロアイコンを押し、Sample1を選択、実行する。
ショートカットはAlt+F8です。今後マクロに本気で取り組むのであれば、覚えておいた方が吉です。

右クリックすると、最下段にButtonメニューが追加されています。

Buttonを押すと、メッセージボックスが表示される。
これで右クリックメニューが追加されました。しかしこの追加メニュー、やっかいな事に削除してやらないとずっと残ったままです(このファイルを閉じても他のファイルにも反映されます)。
削除しないでSample1を実行するとさらに同じものが追加されます。現段階ではSample1を実行したら、Sample2を実行して削除するようにしてください。もちろん、最終的には自動で削除するようにします。
右クリックメニュー追加のサンプルコードを改造する
次に、実際にやりたい事を挙げてみます。今回はこんな仕様にしてみました。
- 追加したメニューを一番上に表示したい
- メニューを2段階のリストにしたい
- 右クリックメニューを表示するのは特定のシートのみにしたい
あとは検索ワードをひねり出して、ひたすらググるのみです。
メニューの表示位置とサブメニューの追加
「VBA 右クリックメニュー 追加 一番上」で検索してみました。この記事にやりたい事リスト1番目と2番目の答えがありました。
コードを参考にして先ほどのコードを改造します。プロシージャ名(マクロ名)とメニュー名も読みやすいように日本語に変えました。
Sub 右クリックメニュー追加()
'Before:= で表示位置(行)、Type:= でコントロールの種類を設定
With CommandBars("Cell").Controls.Add(Before:=1, Type:=msoControlPopup)
.Caption = "無限列車編"
With .Controls.Add 'サブメニューを追加
.Caption = "セリフ1" 'サブメニュー(1段目)の名前
.OnAction = "台詞1"
End With
With .Controls.Add
.Caption = "セリフ2" 'サブメニュー(2段目)の名前
.OnAction = "台詞2"
End With
End With
End Sub
Sub 台詞1()
MsgBox "柱として不甲斐なし"
End Sub
Sub 台詞2()
MsgBox "穴があったら入りたい"
End Sub
Sub メニュー削除()
CommandBars("Cell").Controls("無限列車編").Delete
End Sub

With~End Withのくだりは「動けばいい」の精神で潔く無視しましょう(別の記事で詳しく説明しています)。

右クリックメニュー追加を実行すると1番上にサブメニューが追加されました。
Before:=1の数字の部分で表示位置(上から何行目か)を決めているようです(0にするとエラーになりました)。Type:=msoControlPopupで目的の2段階リスト(サブメニュー)にできました。
特定のシートでのみ、右クリックメニューを表示する
「特定のシート 右クリックメニュー」で検索しました。検索上位を読むと、「ワークシートがアクティブになった(選択された)時」にマクロを実行する方法と「特定のワークシートで右クリックした時」にマクロを実行する方法があるようです。
今回は「特定のワークシートで右クリックした時」に実行するようにします。

シートを一つ追加して下さい(Sheet2を用意する)。
上の記事内のWorksheet_BeforeRightClickイベント1項から4項の手順を実施してSheet1のWorksheet_BeforeRightClickイベントプロシージャを作成して下さい。ここに記述したコードは「ワークシートを右クリックした時」に実行されます。
右クリックメニュー追加をWith~End Withまで切り取って、準備したWorksheet_BeforeRightClickプロシージャ内に貼り付けます。切り取った後、残ったSub 右クリックメニュー追加()とEnd Subは削除して下さい。
Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)'右クリック(の直前)でイベント開始
'右クリックメニュー追加をここに貼り付け
With CommandBars("Cell").Controls.Add(Before:=1, Type:=msoControlPopup)
.Caption = "無限列車編"
With .Controls.Add 'サブメニューを追加
.Caption = "セリフ1" 'サブメニュー(1段目)の名前
.OnAction = "台詞1"
End With
With .Controls.Add
.Caption = "セリフ2" 'サブメニュー(2段目)の名前
.OnAction = "台詞2"
End With
End With
End Sub
Sub 台詞1()
MsgBox "柱として不甲斐なし"
End Sub
Sub 台詞2()
MsgBox "穴があったら入りたい"
End Sub
Sub メニュー削除()
CommandBars("Cell").Controls("無限列車編").Delete
End Sub
エクセル画面に戻って右クリックしてみましょう。

右クリックでイベントが発生し、無事メニューが追加される、のですが…

この状態だとSheet1を右クリックするたびにメニューが増えていきます。「特定のシートで右クリック」をする度に発生する訳ですね。
とりあえず増えたメニューをメニュー削除実行で消します(マクロアイコンから実行して下さい)。全て消し終わったらメニュー削除を右クリックメニュー追加同様に切り取って貼り付けます。貼り付け場所はWith~の前です。

メニューを追加する前に削除する事で差し引きゼロにする訳です。
Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
CommandBars("Cell").Controls("Button").Delete '[メニュー削除]をここに貼り付け
With CommandBars("Cell").Controls.Add(Before:=1, Type:=msoControlPopup)
.Caption = "無限列車編"
With .Controls.Add
.Caption = "セリフ1"
.OnAction = "台詞1"
End With
With .Controls.Add
.Caption = "セリフ2"
.OnAction = "台詞2"
End With
End With
End Sub
Sub 台詞1()
MsgBox "柱として不甲斐なし"
End Sub
Sub 台詞2()
MsgBox "穴があったら入りたい"
End Sub

右クリックすると、エラーが出ました
すると今度はエラーになります。どうも追加メニューがない状態でメニューを削除しようとするとエラーになるようです。

エラーダイアログでデバッグを選択するとVBE画面に戻り、エラー箇所が黄色でハイライトされます。終了を押すと実行中のマクロを終了し、エクセル画面に留まります。
先ほどの記事内でメニューを削除するコードとしてApplication.CommandBars(“Cell”).Resetが書かれていました。これを試してみましょう。
CommandBars(“Cell”).Controls(“Button”).DeleteとApplication.CommandBars(“Cell”).Resetを置き換えてみます。
Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
Application.CommandBars("Cell").Reset '追加したメニューをリセットする
With CommandBars("Cell").Controls.Add(Before:=1, Type:=msoControlPopup)
.Caption = "無限列車編"
With .Controls.Add
.Caption = "セリフ1"
.OnAction = "台詞1"
End With
With .Controls.Add
.Caption = "セリフ2"
.OnAction = "台詞2"
End With
End With
End Sub

エラーになりませんでした。
これでいいじゃんと思ったものの、違いが気になるので「Commandbars Reset Delete 違い」でググりました。
- 自分で追加したメニューを削除するとき…Delete
- 全ての追加メニュー(他人が追加したものも含む)を初期化するとき…Reset
Resetでエラー吐かないならそれでいいかと思った矢先、他サイトにお叱りの言葉が書かれていました。以下引用です。
自分が追加したメニューやコマンドを削除するとき、メニューを初期化するためのResetメソッドは、できるだけ使わないようにしてください。Resetメソッドを実行すると、他のマクロやアドインが追加したメニューやコマンドもすべて削除されてしまうからです。メニューは、あなただけのものではありません。他のマクロやアドインなどがメニューを操作する可能性も十分に考慮して、メニューの追加や削除は慎重に行うようにしてください。
https://www.moug.net/tech/exvba/0080026.html
海より深く反省しました。という事で元々使用していたCommandBars(“Cell”).Controls(“Button”).Deleteでどうにかする事にします。
Deleteが使えなかったのはそもそもエラーのせいです。「VBA エラー」で検索してみます。

エラーが発生した際、処理をスキップする方法がありました。On Error Resume Nextと書けば、ある処理がエラーになってもその次の処理へスキップしてくれるようです。
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 = "セリフ1"
.OnAction = "台詞1"
End With
With .Controls.Add
.Caption = "セリフ2"
.OnAction = "台詞2"
End With
End With
End Sub

無事動きました。が、Sheet2でも追加メニューは表示されたままです。
CommandBars(“Cell”).Controls(“Button”).Deleteが実行されるのはSheet1で右クリックされた時のみです。Sheet1のWorksheetイベントに書いてあるので当たり前ですね。
Sheet2でメニューを無効にするためにどのイベントを利用すればいいか考えます。Worksheet_BeforeRightClickイベントプロシージャを作成する際にちらっと見えたWorksheet_Deactivateが使えそうです。
Deactivateはおそらく「アクティブではなくなった時」って意味っぽいじゃないですか。早速プロシージャを作成してみましょう。
Worksheet_BeforeRightClickイベントプロシージャを作成した時と同じ方法です。イベントでDeactivateを選択して下さい。
Private Sub Worksheet_Deactivate() 'ワークシートがアクティブでなくなった時にイベント発生
On Error Resume Next
CommandBars("Cell").Controls("無限列車編").Delete
End Sub

Sheet2で右クリックをしても追加メニューは現れません。
シートについての処理はこれで完了です。あと一息で完成です。
ブックの処理
色々テストを重ねた結果、
- 他のファイルがアクティブになった時
- ファイルを閉じた時
にメニュー削除の処理をしないとメニューが残ったままになります。シート同様、ファイルについての処理が必要という事ですね。「VBA ファイルを閉じたとき」で検索します。
エクセルでしか操作できないファイルの事をブックと呼ぶそうです(*.xlsx,*.xlsm等の形式で保存されたファイル)。乱暴ですが、今回の記事内ではファイル=ブックと捉えて問題ありません。

エクセルで新規ファイルを作成、保存し、拡張子を.xlsxから.zipに変更すれば、ブックの正体が判ります。
Workbook_BeforeCloseとAuto_Closeの2通りの方法があるようです。それぞれ微妙に違うようですが、アドバイスがありました。
Auto_Closeは以前のバージョンとの互換性を保持するために残されているものですので、特段の理由がなければ、Workbook_BeforeCloseのみを使用した方が良いでしょう。
https://excel-ubara.com/excelvba4/EXCEL240.html
はい、特段の理由はないのでWorkbook_BeforeCloseを使用します。Microsoft Excel Objects内のThisWorkbookに記述しろと書いてあるので、

VBE画面のプロジェクトウィンドウ内のThisWorkbookをダブルクックします。

オブジェクトでWorkbookを選択します。この時勝手にイベントが選択され、プロシージャが生成されますが無視して下さい。

右側のプロシージャからBeforeCloseを選択します。先ほど勝手に生成されたプロシージャは削除します。
Workbook_BeforeCloseイベントプロシージャを作成する際、ちらっとDeactivateの文字が見えたので「他のファイルがアクティブになったとき」の処理もまとめて書きました。
Private Sub Workbook_BeforeClose(Cancel As Boolean) 'ブックが閉じる時にイベントが発生
On Error Resume Next
Application.CommandBars("Cell").Controls("無限列車編").Delete
End Sub
Private Sub Workbook_Deactivate() 'ブックがアクティブでなくなった時にイベント発生
On Error Resume Next
Application.CommandBars("Cell").Controls("無限列車編").Delete
End Sub
いきなりApplication.CommandBars(“Cell”).Controls(“Button”).Deleteになっていますね。Application.を追加しています。以下、理由です。
標準モジュールではアクティブブックがデフォルトのブックになり、ThisWorkbookのモジュールではそのブックがデフォルトのブックになります。ThisWorkbookモジュールでは…
CommandBars(“Cell”).ShowPopup…×誤り。ThisWorkbook.CommandBarsの意味になる
Application.CommandBars(“Cell”).ShowPopup…○正しい。セルのショートカットメニューを表示する
https://vbae.odyssey-com.co.jp/column4/s41502.html

オブジェクトを省略した場合、コードを書く場所によって参照するオブジェクトが変わります。要は今までは省略してもたまたま問題がなかったという事です。この内容は難しいので理解は後回しです。
これで無事完成です。適当に複数のファイルを開いた状態で、右クリックをしてみて下さい。狙った通りの動きになっているはずです。
完成
以下、今回の出来高です。
Sheet1(Sheetモジュール)
'右クリックでメニュー追加
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 = "セリフ1"
.OnAction = "台詞1"
End With
With .Controls.Add
.Caption = "セリフ2"
.OnAction = "台詞2"
End With
End With
End Sub
'シートがアクティブでなくなった時、メニューを削除する
Private Sub Worksheet_Deactivate()
On Error Resume Next
CommandBars("Cell").Controls("無限列車編").Delete
End Sub
ThisWorkbook(Bookモジュール)
'ブックが閉じた時、メニューを削除する
Private Sub Workbook_BeforeClose(Cancel As Boolean)
On Error Resume Next
Application.CommandBars("Cell").Controls("無限列車編").Delete
End Sub
'ブックがアクティブでなくなった時、メニューを削除する
Private Sub Workbook_Deactivate()
On Error Resume Next
Application.CommandBars("Cell").Controls("無限列車編").Delete
End Sub
Module1(標準モジュール)
Sub 台詞1()
MsgBox "柱として不甲斐なし"
End Sub
Sub 台詞2()
MsgBox "穴があったら入りたい"
End Sub
ブックモジュールやシートモジュールはイベントが用意されているので、それをトリガー(きっかけ)としてマクロが実行できました。
標準モジュール内に書いたSubプロシージャは2通りの実行方法がありました。一つはマクロボタンを使って手動で実行する方法、もう一つはブックやシートのイベントプロシージャから呼び出して実行する方法です。
これで右クリックメニューの完成です。機能としてはまだメッセージボックスが表示されるだけですが、右クリックメニューのひな型として今後も使えそうです。サブメニューを増やすのもコピペで簡単にできそうです。
おさらい
- マクロ
エクセルの操作を自動化する機能です。
- VBA
Visual Basic for Applicationsの略で、マクロに使われるプログラム言語です。
- VBE
Visual Basic Edtorの略で、VBAコードを記述するソフトです。
マクロの作成方法はVBEでVBAコードを記述します。
プログラムはSub~End Subで括られ、それが一つの実行単位になります(プロシージャ)。
いかがだったでしょうか?とりあえずググってコピペしただけですが一つのマクロが完成しました。このマクロ、実際に私が初めて作成したマクロとほぼ同じものです。作り方もおおよそこの記事の通りです(かかった時間は言わずもがなですが…)。

初めてVBAに触れた人は、何となく雰囲気を掴めればOKです。今回の成果は「マクロが作成できた事」です。
「VBA入門」でググると、オブジェクト、プロパティ、メソッド、変数といった用語がたくさん出てきます。基礎知識からスタートするのは至極当然のアプローチだと思いますが、この記事は別のアプローチ(とりあえず動くマクロを作成する)で構成されています。頭でっかちになるより、まずはマクロを作成して動かすことが脱初心者の近道だと思います。