VBAの列挙体(Enum)とは
列挙体はかんたんに言えば複数の定数をまとめて宣言ができるものです。定数とは、変えられない値を代入するものであり、VBAではConstをつかって宣言し、宣言と同時に値を決めておくものです。
列挙体を利用するためには、まず宣言セクションでEnumステートメントをつかって宣言をします。ステートメントは異なるものの、別の記事で紹介した「構造体」と同じ方法なのでまとめておぼえるといいでしょう。
宣言した列挙体は、宣言時に指定した範囲(スコープ)で利用できます。
そもそも定数なら、利用する場面がそんなに多くないのではないか。といった疑問をもたれそうですが、使い方の工夫しだいで便利なものとなるので、次の章では列挙体(Enum)をつかうメリットを紹介していきます。
オンラインスクールで現役エンジニアのサポートがあるテックアカデミーがおすすめ。
スキマ時間に学べて仕事も保証。必ず副業、始められます。まずは無料でプログラミング体験
VBAで列挙体(Enum)をつかうメリット
さて、列挙体(Enum)をつかうメリットについてですが、結論から言えば、プログラムのカスタマイズやアップデートがしやすいマクロが作れるようになります。また、列挙型を宣言するとモジュールでのプロシージャで名前まで入力するとメンバーが自動で表示される機能(自動入力補完機能)が使用できるため、VBAのコーティングが楽になります。
アップデートやカスタイズがしやすいとはどういうことか。ですが、これはプログラムが読みやすく、編集がしやすいこととなります。例えば、エクセルの表で商品のIDや商品名、仕入価格や販売価格データを以下のようにまとめていたとします。
行/列 | A列 | B列 | C列 | D列 |
---|---|---|---|---|
1行 | 商品ID | 商品名 | 仕入価格 | 販売価格 |
2行 | Sample-001 | 商品A | 100 | 180 |
3行 | Sample-002 | 商品B | 200 | 360 |
4行 | Sample-003 | 商品C | 300 | 540 |
エクセルのデータは表形式なので縦(行)と横(列)の形式が基本ですが、このデータのうち、商品Aの販売価格の値を取得する場合のVBAのコードであれば、以下のように想定ができます。
商品Aの販売価格を取得するVBAコード
Sheet1.Range(“D2”).value
または、
Sheet1.Cells(2,4).value
※表はSheet1に書かれているものとします。
しかし、ある日、この表のB列とC列の間に該当商品の「メーカー名」を挿入することになった場合はどうなるでしょうか。以下に列を追加した表を掲載しておきます。
行/列 | A列 | B列 | C列 | D列 | E列 |
---|---|---|---|---|---|
1行 | 商品ID | 商品名 | メーカー名 | 仕入価格 | 販売価格 |
2行 | Sample-001 | 商品A | XX株式会社 | 100 | 180 |
3行 | Sample-002 | 商品B | 株式会社YY | 200 | 360 |
4行 | Sample-003 | 商品C | 合同会社ZZ | 300 | 540 |
D列に入力されている「販売価格」はB列とC列の間に追加された「メーカー名」が挿入されることで、E列になってしまい、先に書いたマクロで取得できる値は商品Aの情報は「販売価格」から「仕入価格」になります。
もし、こちらのマクロで請求書を発行する処理を実施していた場合、販売価格ではなく、仕入価格による請求書が発行されてしまって大惨事といったことにもなりかねません。
また、このアップデートに対応するために、値を取得するために指定していた「Sheet1.Range(“D2”).value」や「Sheet1.Cells(2,4) .value」が使われている部分を膨大なコードの中からすべて見つけて「Sheet1.Range(“D2”).value」なら「Sheet1.Range(“E2”).value」に、「Sheet1.Cells(2,4) .value」なら「Sheet1.Cells(2,5) .value」に修正していく作業は、非常に神経をすり減らす作業となってきます。
なお、プログラミングにおいて製作者しかわからないような直に書かれた数値をマジックナンバーと呼びますが、プログラミングでは、このマジックナンバーはなるべく使用しないことが望ましいとされています。これはマジックナンバーがあると、製作者以外には数値の意図や意味が理解できず、VBAのコードが読みにくくなるからであるからです。
また、これはほかの人と協力してシステムを開発するエンジニアだけに限ったわけではなく、1週間、数ヵ月、数年後の自分と、そのマクロを制作した時点の自分との間にも当てはまってくるでしょう。
これらについて列挙体(Enum)をつかうことで解消することができます。
ここで紹介したあるデータが書かれた表に列が挿入された場合であっても、列挙体(Enum)で宣言したものの値を変更するだけでアップデートが完了することができます。
では、どのようにすれば良いかの詳しい内容は、後述のサンプルマクロで解説しますが、まずは列挙体(Enum)のつかいかたについて次の章で紹介します。
VBAで列挙体(Enum)のつかいかた
本章では、列挙体のEnumステートメントをつかって宣言します。
列挙体(Enum)の構文
列挙体(Enum)の構文
[ Public | Private ] Enum 列挙型名(name)
メンバー名(membername)1 [=値(constantexpression)]
メンバー名(membername)2 [=値(constantexpression)]
End Enum
構文だと難しくみえるけど、引数や書きかたについて次から見ていくよ。
列挙体(Enum)の引数について
引数については以下のとおりです。
引数の種類 | 必須Or省略可能 | 省略時の値 | 説明 |
---|---|---|---|
列挙体名 (name) |
必須 | – | 列挙体の名前を指定します。 |
メンバー名 (membername) |
必須 | – | 列挙体を構成するメンバーの名前を指定します。 |
値(constantexpression) | 省略可能 | 長整数型(Long)の値が代入されます。 先頭のメンバーの場合は0が、それ以降のメンバーなら直前のメンバーの値に+1がされた数値が代入されます。 |
数値を指定します。長整数型(Long)の値を代入します。 |
列挙体(Enumステートメント)は宣言セクションでのみ使用が可能です。
プロシージャ内で記入した場合はコンパイルエラーが発生します。また、宣言セクションでメンバーに指定した値をプロシージャで変更しようとした場合も同じくコンパイルエラーが発生します。つまり宣言時に指定した値からは変更できません。
ここまでで、列挙体(Enum)の基本的な使いかたを見てきましたので、続いて列挙体(Enum)を使ったサンプルマクロを見ていきましょう。
なぜ、膨大な事務作業でも定時で退社できるのか。
実務をプロから学べる「ユースフル」の動画は永年見放題。Q&A機能で分からないを放置しないから安心。
詳しくは以下のリンクをクリック
VBAで列挙体(Enum)をつかったサンプルマクロ
この章では列挙体(Enum)をつかったサンプルマクロを紹介します。
まずは、シンプルに列挙体(Enum)を宣言して、デバッグプリントでイミディエイトウィンドウに列挙体(Enum)のメンバーに指定した値を出力するマクロです。
列挙体(Enum)をつかったサンプルマクロ1
Option Explicit '宣言セクションで列挙体(Enum)を宣言 Private Enum 商品データ見出し 商品ID = 1 商品名 = 2 仕入価格 = 3 販売価格 = 4 End Enum 'プロシージャで列挙体(Enum)のメンバーをデバッグプリントで出力する Sub Enum_test() Debug.Print 商品データ見出し.商品ID '実行結果:1 Debug.Print 商品データ見出し.商品名 '実行結果:2 Debug.Print 商品データ見出し.仕入価格 '実行結果:3 Debug.Print 商品データ見出し.販売価格 '実行結果:4 End Sub
宣言セクションで列挙体を宣言します。Enumステートメントをつかって、メンバー名にイコールで値を代入します。プロシージャ(Enum_test)ではデバッグプリントでメンバーの値を出力しています。
つづいて、メンバーの値を省略した場合のケースになります。
列挙体(Enum)をつかったサンプルマクロ2(メンバーの値を省略)
Option Explicit '宣言セクションで列挙体(Enum)を宣言 Private Enum 誕生石 ガーネット '1月の誕生石 アメジスト '2月の誕生石 アクアマリン = 3 '3月の誕生石 ダイヤモンド = 4 '4月の誕生石 エメラルド = 5 '5月の誕生石 パール = 6 '6月の誕生石 ルビー '7月の誕生石 ペリドット '8月の誕生石 サファイア = 90 '9月の誕生石 オパール '10月の誕生石 トパーズ '11月の誕生石 トルコ石 '12月の誕生石 End Enum 'プロシージャで列挙体(Enum)のメンバーをデバッグプリントで出力する Sub Enum_test2() Debug.Print 誕生石.ガーネット '実行結果:0 値を指定しない最初のメンバーは0 Debug.Print 誕生石.アメジスト '実行結果:1 2つ目以降のメンバーは直前のメンバーの値に+1 Debug.Print 誕生石.ルビー '実行結果:7 直前のメンバーの値が6なので7 Debug.Print 誕生石.サファイア '実行結果:90 値を指定しているので90 Debug.Print 誕生石.オパール '実行結果:91 直前のメンバーの値が90なので91 End Sub
最初のメンバーの値が省略された場合は0になること、それ以降は直前のメンバーの値に+1がされた値が代入されていることがわかります。なお、メンバーの値はほかのメンバーと同じでもエラーが発生することはありません。
次は、エクセルの表からデータを取得するマクロです。以下の表からデータを取得します。
次のマクロは、ユーザーより入力された数量を受け取って、販売価格の合計、仕入価格の合計と利益を返す処理を実行します。テストでは数量の入力で10を指定しています。
列挙体(Enum)をつかったサンプルマクロ3(エクセルの表の列数をメンバーにする)
Option Explicit '宣言セクションで列挙体(Enum)を宣言 Private Enum 商品データ見出し列 'エクセルの表の列数をメンバーに代入 商品ID = 1 商品名 = 2 仕入価格 = 3 販売価格 = 4 End Enum 'プロシージャで列挙体(Enum)のメンバーを利用して処理をする Sub Enum_test3() Dim n As Long With Worksheets("商品データ") n = Application.InputBox("商品の販売数量を入力してください。", "数量の入力", 1, Type:=1) '10を入力 '販売価格の合計を計算してメッセージボックスで表示する MsgBox ("販売価格の合計:" & .Cells(2, 商品データ見出し列.販売価格) * n & "円です") '仕入価格の合計を計算してメッセージボックスで表示する MsgBox ("仕入価格の合計:" & .Cells(2, 商品データ見出し列.仕入価格) * n & "円です") '利益を計算してメッセージボックスで表示する MsgBox ("利益:" & .Cells(2, 商品データ見出し列.販売価格) * n - .Cells(2, 商品データ見出し列.仕入価格) * n & " 円です") End With End Sub
このマクロと同じ処理を、列挙体(Enum)をつかわなかった場合も比較用に掲載しておきます。
列挙体(Enum)をつかわずにサンプルマクロ3と同じ処理をする
Option Explicit Sub NoEnum_test() '列挙体(Enum)を使わないで処理をする Dim n As Long With Worksheets("商品データ") n = Application.InputBox("商品の販売数量を入力してください。", "数量の入力", 1, Type:=1) '10を入力 '販売価格の合計を計算してメッセージボックスで表示する(180円×10個) MsgBox ("販売価格の合計:" & .Cells(2, 4) * n & "円です") '仕入価格の合計を計算してメッセージボックスで表示する(100円×10個) MsgBox ("仕入価格の合計:" & .Cells(2, 3) * n & "円です") '利益を計算してメッセージボックスで表示する(1,800円-1,000円) MsgBox ("利益:" & .Cells(2, 4) * n - .Cells(2, 3) * n & " 円です") End With End Sub
列挙体(Enum)をつかわずに列数の値を指定することで実現しています。ここまでであれば、VBAのコード量も短いですし、列挙体(Enum)をつかうメリットは感じられないと思います。しかし、列挙体(Enum)のメリットを紹介する章でもお伝えしたとおり、表に新たな列を追加することになったと考えてみましょう。
変更内容は、元の表データのC列(商品名)とD列(仕入価格)の間に新たに「メーカー名」を挿入したこととします。
実際に追加した表を以下に掲載します。
さて、このように表が変更されたことで、サンプルマクロはどのようなアップデートが必要になるか見ていきましょう。さきに列挙体(Enum)をつかって作成したマクロの場合のアップデートは以下のようにします。
列挙体(Enum)をつかったサンプルマクロ3のアップデート
Option Explicit '宣言セクションで列挙体(Enum)を宣言 Private Enum 商品データ見出し列 'エクセルの表の列数をメンバーに代入 商品ID = 1 商品名 = 2 メーカー名 = 3 'メンバーにメーカー名を追加し、列数を調整 仕入価格 = 4 'メンバー追加に伴い列数を調整 販売価格 = 5 'メンバー追加に伴い列数を調整 End Enum 'プロシージャで列挙体(Enum)のメンバーを利用して処理をする Sub Enum_test3() Dim n As Long With Worksheets("商品データ") n = Application.InputBox("商品の販売数量を入力してください。", "数量の入力", 1, Type:=1) '10を入力 '販売価格の合計を計算してメッセージボックスで表示する(180円×10個) MsgBox ("販売価格の合計:" & .Cells(2, 商品データ見出し列.販売価格) * n & "円です") '1,800 '仕入価格の合計を計算してメッセージボックスで表示する(100円×10個) MsgBox ("仕入価格の合計:" & .Cells(2, 商品データ見出し列.仕入価格) * n & "円です") '1,000 '利益を計算してメッセージボックスで表示する(1,800円-1,000円) MsgBox ("利益:" & .Cells(2, 商品データ見出し列.販売価格) * n - .Cells(2, 商品データ見出し列.仕入価格) * n & " 円です") End With End Sub
表の更新にともなって書きかえた部分は、赤色のマーカーをした部分のみです。プロシージャにいたってはさわることさえしていません。とてもスピーディーで安全にアップデート対応ができました。これこそが列挙体(Enum)で指定した場合の最大のメリットと言えます。
一方で、列挙体(Enum)をつかわずに処理していたマクロのアップデートはどうでしょうか。
Option Explicit Sub NoEnum_test() '列挙体(Enum)を使わないで処理をする Dim n As Long With Worksheets("商品データ") n = Application.InputBox("商品の販売数量を入力してください。", "数量の入力", 1, Type:=1) '10を入力 '販売価格の合計を計算してメッセージボックスで表示する(180円×10個) MsgBox ("販売価格の合計:" & .Cells(2, 5) * n & "円です") '列数を4から5に変更 '仕入価格の合計を計算してメッセージボックスで表示する(100円×10個) MsgBox ("仕入価格の合計:" & .Cells(2, 4) * n & "円です") '列数を3から4に変更 '利益を計算してメッセージボックスで表示する(1,800円-1,000円) MsgBox ("利益:" & .Cells(2, 5) * n - .Cells(2, 4) * n & " 円です") '列数を3→4、4→5に変更 End With End Sub
こちらは列挙体(Enum)を使っていないため、プロシージャのコードを編集する必要がでてきます。
赤色のマーカー部分が編集した部分になりますが、列挙体(Enmu)を使ったものと比較すると、影響範囲がコードのあちらこちらに散ってしまうので、アップデートの対応がどこまでなのかがみきわめにくいです。
さらにVBAのコード量が増えれば増えるほど、アップデートのしやすさに明確な違いが出てきますので、列挙体(Enmu)を使う効果が実感できると思います。
列挙体(Enum)を使っていれば、マクロのアップデートがカンタンだね。
つづいてはエラーが発生するサンプルマクロを紹介していきます。
VBAで列挙体(Enum)でエラーが発生するケース
こちらでは、引き続き列挙体(Enum)を使ったサンプルマクロでエラーとなるケースを紹介していきます。列挙体(Enum)を使うマクロの作成時の参考にしてください。
列挙体(Enum)をつかったサンプルマクロ4(メンバーの値に長整数型以外を指定)
Option Explicit '宣言セクションで列挙体(Enum)を宣言 Private Enum 組みわけ グリフィンドール = 1 ハッフルパフ = 2 レイブンクロー = 3 スリザリン = "A" '文字列を代入しようとするとエラーが発生する End Enum 'プロシージャで列挙体(Enum)のメンバーの値を変更しようとする Sub Enum_test_error() 'デバッグプリントで代入した値を出力する Debug.Print 組みわけ.グリフィンドール Debug.Print 組みわけ.ハッフルパフ Debug.Print 組みわけ.レイブンクロー Debug.Print 組みわけ.スリザリン End Sub
列挙体(Enum)をつかったサンプルマクロ5(メンバーの名の重複)
Option Explicit '宣言セクションで列挙体(Enum)を宣言 Private Enum 組みわけ 'メンバー名が重複しているため実行エラーが発生する グリフィンドール = 1 ハッフルパフ = 2 レイブンクロー = 3 グリフィンドール = 10 End Enum 'プロシージャで列挙体(Enum)のメンバーをデバッグプリントで出力する Sub Enum_test_error() Debug.Print 組みわけ.グリフィンドール End Sub
列挙体(Enum)をつかったサンプルマクロ6(メンバーの値を変更しようとする)
Option Explicit '宣言セクションで列挙体(Enum)を宣言 Private Enum 組みわけ グリフィンドール = 1 ハッフルパフ = 2 レイブンクロー = 3 スリザリン = 4 End Enum 'プロシージャで列挙体(Enum)のメンバーの値を変更しようとする Sub Enum_test_error() 組みわけ.グリフィンドール = 5 End Sub
列挙体(Enum)をつかったサンプルマクロ7(プロシージャのなかに列挙体の宣言文がある)
Option Explicit '宣言セクションで列挙体(Enum)を宣言 Private Enum 組みわけ グリフィンドール = 1 ハッフルパフ = 2 レイブンクロー = 3 スリザリン = 4 End Enum 'プロシージャで列挙体(Enum)を宣言するとエラーが発生する Sub Enum_test_error() 'プロシージャで列挙体(Enum)名「組みわけ2」の宣言文 Enum 組みわけ2 ゴドリック = 1 ヘルガ = 2 ロウェナ = 3 サラザール = 4 End Enum Debug.Print 組みわけ2.サラザール; "・"; 組みわけ.スリザリン End Sub
列挙体(Enum)をつかったサンプルマクロ8(同じスコープ(適用範囲)内に列挙体名が重複している)
'標準モジュール1 Option Explicit '宣言セクションで列挙体(Enum)を宣言 Enum 組みわけ 'スコープの指定を省略した場合は既定値に従い「Public」となる グリフィンドール = 1 ハッフルパフ = 2 レイブンクロー = 3 スリザリン = 4 End Enum
'標準モジュール2 Option Explicit '宣言セクションで列挙体(Enum)を宣言しているが、標準モジュール1の列挙体名と重複している Public Enum 組みわけ 桔梗組 = 1 菊組 山茶花組 椿組 華組 牡丹組 桃組 楼組 End Enum Sub Enum_test_error() Debug.Print 組みわけ.山茶花組 End Sub
どちらかの列挙体のスコープを「Private」に変更するとエラーは出なくなるよ。
VBAで列挙体(Enum)まとめ
この記事では、VBAで列挙体(Enum)と呼ばれるものについて紹介してきました。列挙体(Enum)は複数の定数(変化しない固定の数値)をまとめて宣言し、処理に利用することができるものです。また、列挙体(Enum)を利用するメリットは、VBE上でインテリセンス(自動入力補完機能)の利用ができることと、マクロのアップデートやメンテナンスがしやすくなるといったものでした。
さいごに箇条書きでこちらの記事をまとめておきます。
- 列挙体(Enum)を使うメリット
- 列挙体(Enum)を使いかた
- 列挙体(Enum)を使うときの注意点
列挙体(Enum)を使わなくてもマクロが作れないわけではないですが、プログラミングスキルでは、いかに読みやすいコードを書いて、修正やアップデートを安全にできるようにそなえておくかも大切です。便利なものを適切な場所で柔軟に利用するチャレンジを続けることで幅広い知識が身につくようになるでしょう。
あなたのマクロをつくるためにこちらの記事が少しでもお役にたてば幸いです。
コダマのもりブログはにほんブログ村に登録しています。
ブログの記事が役に立ったと感じて頂けたら、フォローお願いいたします。
コメント