どうも。つじけ(tsujikenzo)です。こちらのシリーズでは2021年1月より受講しました「ノンプロ研VBA中級講座2期」で学んだことをアウトプットしております。本日はドキドキのDay1です。
前回の講座
2020年11月よりVBA初級講座3期を受講していました。無事卒業LTまでやりましたが、訂正しなければならない内容も沢山あったみたいです💦
受講者宣誓
私にとってVBAは第3言語目ですが、初級の時点で分からないことが多く、戸惑っています。プロパティの仕組みが違うのかな?という印象です。
とはいえ、Twitterなどで諸先輩達が「VBAの○○の仕様は謎」とつぶやいているのを見ると、プログラミング言語としての考察はほどほどにして、「実務で使えるツールを作ること」に集中したほうがいいかなと思ったりもしています。
後は、講師が執筆された「パーフェクトVBA」を受講のお供にさせていただきます。
自己紹介
Slackだと流れてしまうので、自己紹介も残しておきます。
つじけです。ノンプロ研では唯一受けていない講座がVBA中級でした。これから登ろうとしている山の麓に立って、見上げている気分です。
今日はこちらも雪が沢山降っていたせいでしょうか、見上げている山がとてつもなく厳しい山 に見えます。
「なぜ中級講座を受講したのか?」
なぜでしょうね。GASと出会って「これからは完全にクラウド化に移行する!」と思ったけど「やっぱりExcelは捨てない。だって皆Excelだもん」って感じです。なので「より多くの人を喜ばせることができるから」が答えかもです。
「講座を通して何を実現したいのか」
なので社内ツールはほぼGASなので「実務で使う」というのが難しいです。取引先でGASが使えない人たちの業務改善をするのが一番私に合ってるアウトプットかも知れませんね。学習のアウトプットとして「VBA Expert Standard Crown」を取るのも視野にあります。
ちょっと語り口調なのは並行してライティング講座を受けているからです!気にしないで下さい!宜しくお願い致します
それでは、さっそくはじめて行きたいと思います。前半が「スコープ」、後半が「プロパティとPropertyプロシージャ」となっております。
スコープ
宣言ステートメントは、変数、定数、プロシージャなどを定義するステートメントです。宣言ステートメントを記述することで、その定義した対象を使用することができます。ただし、その宣言ステートメントの記述する場所や、記述内容に応じて、それらを参照したり、呼び出したりできる範囲が制限されます。その使用できる範囲のことをスコープといいます。
パーフェクトVBA
『プロシージャレベルのスコープでは、プロシージャを指定することはできない』というのがポイントだと思いました。
変数の宣言
Dim宣言
変数は値を格納できる名前付きの保存場所で、プロシージャレベルの変数を宣言するには、使用するプロシージャ内でDimステートメントを使用します。
Dim varname As データ型
Private宣言
モジュールレベルで宣言する際の宣言ステートメントは、宣言セクションと呼ばれるエリアに記述をします。~中略~プライベートモジュールレベルの変数を宣言するには、Privateステートメントを使用します。
(宣言セクションで)
Private 変数名 As データ型
Public宣言
パブリックモジュールレベルの変数は、プロジェクト内の他のモジュールからも使用が可能です。いずれかのモジュールの宣言セクションでPublicステートメントを使用します。
(宣言セクションで)
Public 変数名 As データ型
モジュールレベル変数の宣言ステートメントでは[Public|Private]を省略することはできません。必ず記述しましょう。プロシージャと引数
VBAの最大の特徴である、5つのプロシージャ。Subプロシージャは手続きの固まりで、同じプロシージャでも戻り値を返す手続きをFunctionプロシージャと、あえて区別しているのは初級講座で既に理解しました。
(講座中に「なぜSubとFunctionプロシージャが分かれてるのかな?」ってつぶやいた人がいて、「BASICのSubルーチン、戻り値が無くてPublic変数使ってた」ってつぶやきもあってビックリ。)
この節ではプロシージャのスコープと、引数リストなどのテクニックについて理解を深めます。
プロシージャにも[プライベート/パブリック]モジュールレベルの2つのレベルのスコープがあります。~中略~マクロが単一のモジュールで構成されているものであれば、省略されているパブリックプロシージャで問題ありませんが、複数のモジュールでマクロを構成する場合は、スコープを意識する必要があり、パブリックプロシージャといえども明示するようにするとよいでしょう。
パーフェクトVBA
省略せずにPublicと書くようにした方が良さそうですね。
[Private|Public] Sub プロシージャ名(引数リスト) '処理 End Sub
同様に、Functionプロシージャにも[プライベート/パブリック]モジュールレベルを指定することができます。私もTAさんを見習って、Publicステートメントも省略しない書き方をしていこうと思いました。
Subプロシージャの呼び出し
Sub プロシージャを他のプロシージャから呼び出すときは、Callステートメントを使います。
Call プロシージャ名(引数リスト)
または
プロシージャ名 引数リスト
Callを省略するかしないかで引数リストの()が必要か不要か変わるので注意が必要です。引数の構文
プロシージャが引数を受け取る場合には、その宣言ステートメントに引数リストを記述します。引数リストには、引数に対するパラメータ名とデータ型だけでなく、様々な機能的な指定をすることができます。
Sub name([arglist])
[statements]
End Sub
丸かっこ内の引数リストarglistに、以下で表す書式を、受け取る引数の数だけカンマ区切りで指定します。
[Optional][ByVal | ByRef][ParamArray] varname[()] [As type] [ = defaultvalue]
デフォルト引数を使う時はOptionalを省略するとコンパイルエラー出ます。必ずセットで記述します。
さて、前半戦は以上です。まだ大丈夫でしょうか。これから後半戦です。難しくないけど、「1つでも飛ばして学習を進めると結局後になってもう一度学習しないといけない」というゾーンに突入します💦
プロパティとPropertyプロシージャ
まずは単語の定義です。「プロパティ」とは、
モジュールレベル変数や3種のPropertyプロシージャを組み合わせた、値を取得・設定する機能
パーフェクトVBA
です。これを見ただけでは理解できなくて大丈夫です。いつも言っているように、「どんな仕組み」を理解する為に、まずは「書き方・使い方」を徹底して覚えましょう。
プロパティの書き方は、以下の3つです。
- モジュールレベル変数(Public|Private)
- Property Let/Setプロシージャ
- Property Getプロシージャ
一つずつ見ていきましょう。
モジュールレベル(パブリック変数)によるプロパティの定義
VBAでもっとも簡単にプロパティを作る方法は、モジュールレベル(パブリック変数)で変数を宣言することです。今回は[標準モジュール]の[モジュールレベル]に、[パブリック変数]で宣言します。(3つの単語が分からない時は復習して戻ってきましょう)
標準モジュール[Module1_3]
Public price As Long
それでは使い方(呼び出し)です。別の標準モジュール[Day1]を用意して、[サブプロシージャ]の中で値の代入とデバッグウィンドウで値の出力をします。標準モジュール[Module1_3]
Public price As Long
標準モジュール[Day1]
Sub MySub()
price = 100
Debug.Print price
End Sub
イミディエイトウィンドウには100が表示されています。
オブジェクトブラウザの確認
[オブジェクトブラウザ]で[VBAProject]を開き、[Module1_3]に記述した変数priceを確認してみましょう。
変数priceは、Module1_3のメンバー(アイコンはプロパティ)になっていることが確認できます。
入力補完の確認
先ほどのコードですが、オブジェクトを省略せずに記述するとこのようになります。
標準モジュール[Module1_3]
Public price As Long
標準モジュール[Day1]
Sub MySub()
Module1_3.price = 100
Debug.Print Module1_3.price
End Sub
そして、標準モジュール[Day1]のSub MySub()を写経する際に、Module1_3.と入力すると、入力補完として[price]が表示されました。
つまり、変数priceは標準モジュール[Module1_3]のメンバーになっており、どこからでも呼び出すことができるということです。(ここ大事です覚えておきましょう💦)
ミニまとめ
標準モジュールのモジュールレベルにパブリック変数を定義すると、他の標準モジュールから、モジュール名.変数で呼び出すことができる(モジュール名は省略することができる)。
これは、標準モジュールのパブリック変数が、標準モジュールのメンバー(プロパティ)になっていることを示している。
「あれ?そしたら標準モジュールってオブジェクトなの?」という疑問を持った方は素晴らしいです。そっと胸の内にしまっておいてください。(後で回収します)
Property Let/Setプロシージャ
[プロパティ]の定義はパブリック変数だけでなく、Property Let/Setというプロシージャでも可能です。プロシージャなので、引数を渡すと結果としてプロパティを生成するというものです。
- Property Letプロシージャ・・・値(オブジェクト以外)を設定する
- Property Setプロシージャ・・・オブジェクトの参照値を設定する
オブジェクト変数をSetで定義していたので、見覚えがあるかもしれません。Letは普段から省略されているものでもあります。
[Private|Public] Property {Let|Set} プロシージャ名(引数リスト, 値)
'処理
End Property
定義される[Value]は必須項目です。 プロパティに割り当てる値を格納している変数です。 プロシージャの呼び出し時に、この引数は呼び出し元の式の右辺に置きます。 value のデータ型は、対応する Property Get プロシージャの戻り値の型と同じにする必要があります。
[Let] プロシージャ名[(引数リスト)] = 値
Set プロシージャ名[(引数リスト)] = オブジェクト
コードで確認してみましょう。
Option Explicit
Private price_ As Long
Sub MySub1_12()
Price = 100
Debug.Print price_
Price = -100
Debug.Print price_
End Sub
Property Let Price(ByVal newPrice As Long)
If newPrice >= 0 Then price_ = newPrice Else price_ = 0
End Property
Sub mysub_test()
Debug.Print price_
End Sub
オブジェクトブラウザでも確認してみましょう。プロパティ[Price]を生成できています。
Property Getプロシージャ
Property Let/Setプロシージャはプロパティを設定するためのプロシージャでしたが、プロパティを取得するためのProperty Getプロシージャがあります。
先ほどPrivate変数を、プロパティの値の保管場所として使用しましたが、この値を取り出してなんらかの処理をして返す、というプロシージャがProperty Getプロシージャです。
構文は戻り値を最後に指示するところなど、Functionプロシージャと似ています。
[Private|Public] Property Get プロシージャ名(引数リスト) As 型
'処理
プロシージャ名 = 値
End Property
呼び出し方も「プロシージャ名[(引数リスト)]」ですので、引数が無ければ変数と同じように呼び出せます。これはGASのゲッターセッターと同じで、代入の時はProperty Letプロシージャ、呼び出しの時はProperty Getプロシージャが実行されるものです。
ゲッターセッターについては、もう一度あとで復習してみたいと思います。
まとめ
さて、事前課題も含まれていますので、だいぶ長くなりましたが、Day1をやっと終えることができました。講師も仰ってましたが、Day1が一番キツイかもしれません💦
途中「何かがわからない」状態に陥って、何がわからないのか整理したところ、自分は「スコープ」がわかってないんだということが分かり、スコープについて考察をしていました💦スコープの記事3本を書くのに1週間以上使ったかもしれません。。。いつか公開します。(答え合わせは「クラス」について学んでからにします)
次回は「モジュール」についてお届けします。