どうも。つじけ(tsujikenzo)です。こちらのシリーズではノンプロ研VBA初級講座3期で学んだことをアウトプットしております。本日は3回目と4回目です。バタバタしておりますが、1つずつやっつけて行きましょう。
Day3 プロシージャ、関数
VBAには4~5種類のプロシージャがあってややこしいのは「パーフェクトVBA」を読んで知ってましたが、知らないことが沢山ありますね。
Callステートメント
講師に『謎』と言わせるCallステートメントの省略記法。Subプロシージャの呼び出しにはCallと実引数(がある時は)カッコを付けると覚えようw
「謎」と言うのは以下のような挙動を言うのかしら。
- Callを付けると後ろに()が付けると自動で消える。。。
- Call無しで()付けるとエラーになる。。。
- 引数があれば省略もエラーにはならない。。
授業ではSubプロシージャを呼び出すときはCallをつけようと言っていたが、functionプロシージャも挙動はほぼ同じで、functionプロシージャは関数だから呼び出す時に違いをつけといて分かりやすくしようという暗黙のルールなのからしら。
そして、仮引数を受ける時はDimension定義要らないのかよ。。。
参照渡しと値渡し
夏にLTをやった時にVBAで例えてみたので覚えていた。ByRefはデフォルト。省略可。
関数
関数は「戻り値を持つプロシージャ」って言語化できるのか。なるほど。
Functionプロシージャ・・・関数を作るプロシージャ
さらに戻り値を得る為にはFunctionプロシージャで呼び出しが必要なのか。他の言語だとreturnで戻せるけど。。。戻り値を再代入しているイメージ。最終処理の値が戻る。
Sub MySub()
Debug.Print Square2(5)
End Sub
Function Square2(x As Long) As Long
Square2 = x ^ 2
End Function
なお、仮引数で受け取る型は厳密に合ってなくても合わせようと努力をして動く。しかし論理エラーを起こすので厳密に書く方が無難。同じように戻り値に対しても型を指定するが、型が合ってなくても動くけど合わせよう。配列などで返ってくるときはAs Variantで待ち受ける。
カッコつける?
これも他の言語との切り替えが大変なやつですが、返り値を変数に格納するときは付ける、逆は付けないルールだそうです。(TAのtakushiさんありがとうございました。)
Dim ws As Worksheet
'動く書き方
Worksheets.Add
Worksheets.Add before:=Worksheets(1)
Set ws = Worksheets.Add
Set ws = Worksheets.Add() '動くけどこの書き方は見たことないかもしれません
Set ws = Worksheets.Add(before:=Worksheets(1))
'エラーになる書き方
Worksheets.Add()
Worksheets.Add(before:=Worksheets(1))
Set ws = Worksheets.Add before:=Worksheets(1)
VBA関数?
は、初めて聞いた。VBA関数とはVBAに当初から用意されている関数(≠ワークシート関数)でVBAライブラリに含まれている。
VBA関数の一覧を確認するのもF2[オブジェクトブラウザー]から。
行連結シーケンス
「 _」(半角スペース+アンダースコア):行連結シーケンス → ステートメントを改行
Date関係は手を動かして慣れるしかない気もするけど。忘れてもリファレンスを見れば動かせそうなので気にしないことにした。宿題が解けてよかった。挫折しそうだった。。。💦
Day4 オブジェクト・コレクション
今日のアジェンダ。。。。なんだか重くなってきたな。ついていけるか。
1.オブジェクトとコレクション
2.オブジェクト式とオブジェクト変数
3.コレクションのループ
コレクションはオブジェクトの集まり。
オブジェクトとコレクション
なんとなくオブジェクトというのはわかる。操作しようとする全てはオブジェクト。
知らなかったことはF2[オブジェクトブラウザー]でExcelライブラリを確認することができる点。
オブジェクトブラウザ
オブジェクトブラウザのアイコン
メンバーの「プロパティ」か「メソッド(Function)」なのかの違いは私でも理解できそうです。(他にも定数やイベントというアイコンがありますが、理解を割愛させていただきます。)
同じようにクラスペインにもアイコンがあるようで、(こちらはVBA関数のライブラリです)ぱっと見ただけでも3種類ありまして、
- クラス・オブジェクト
- モジュール
- 列挙型・列挙体
がありそうです。アイコンが違うのです。何かが違うのでしょう。今日は中級講座じゃないのです。その区別の理解は後々の楽しみに取っておきましょう。
ちなみにイミディエイトウィンドウでオブジェクトに続いてピリオドを押すとメンバー候補が現れます。自分が操作しようとしているオブジェクトが何オブジェクトなのか、メンバー一覧から推測することも可能でしょう。(そんなことは講師は言っていない
コレクション
複数の同種のオブジェクトの集まりがコレクション?これなんなんだろ。自分で定義できる?あらかじめこのオブジェクトにはこのコレクション名みたいに決まってるもの?
厳密にはコレクションもオブジェクトですがわかりやすさのために集合はコレクション、単品はオブジェクトと呼んで進めていく。複数あるWorkbookオブジェクトのコレクションはWorkbooksコレクションですとのこと。
コレクションは理解というより慣れるしかなさそう。今はこういうもんだと思っておこうw
オブジェクト式とオブジェクト変数
写経してる時に疑問に思った。「Sheet1とかWorkbooksってどっから来たの?」と思ったら、これはユーザーが自由に記述したもの。(しかしSheet1がシートオブジェクトってどうやって判定してるんだろ・・・)
正解は、、、「オブジェクトにはオブジェクト式と呼ばれる、オブジェクトを生成する式がある」です。
Sub MySub4_01()
Debug.Print Sheet1.Name ‘オブジェクト
Sheet1.Name = "テスト"
Debug.Print Sheet1.Name
End Sub
Sub MySub4_03()
Debug.Print Workbooks.Count ‘コレクション
Workbooks.Add
Debug.Print Workbooks.Count
End Sub
オブジェクト式の作り方のパターン1.オブジェクト名を使う
なるほど。コード内で使えるオブジェクトの名前をオブジェクト名にするパターン。
- Workbook → ThisWorkbook
- Worksheet → Sheet1, Sheet2, …
(でもブック名、シート名とどう違うんだろ。)って思ってたらオブジェクト名をここ(プロジェクトエクスプローラー&プロパティウィンドウ)で確認できるの知らなかったー。
つまり、GASで例えると(あんまり例えちゃいけないけども)、SpreadSheetのシート名とシートIDが別々に用意されてるように、そしてどちらでも操作できるような感覚。VBAの場合Sheet1みたいな名前なのでややこしい。ただし、名前を変えることができるので、ユニークに与えられるGASのオブジェクトIDとも違うのでややこしや。(だから例えるなって言ったでしょ💦)
オブジェクト式の作り方のパターン2.プロパティを使う
オブジェクトは階層構造になっており、親から子という流れでオブジェクト式を作ることができる。
なので、配下にぶら下がってる(含まれている)オブジェクトやコレクションを下記のようなプロパティで取得することができる。
親がいれば子どもがわーっといるのでがさーっと格納するのがコレクションですね。
F2[オブジェクトブラウザ」でWorksheetsプロパティを確認してみましたが、「コレクション、コレクションとしても使える」って書いてるのかなぁって薄く期待したけど無かった。
さらに、コレクション(インデックス)を使うことで、コレクションは複数だけど、インデックスを指定することで、同様にコレクション(名前)で単品でオブジェクトを指定することもできるわけです。
上位オブジェクトの指定の省略
だけど毎回毎回上位オブジェクトをリテラルに記述するのは長くなるから、こういう条件下で省略しようよってルールがあります。(VBAって結構省略記法が多い気がする。知らないと詰むところかも。)
プロパティカラムにあるプロパティはグローバルで使えるプロパティになります。
Debug.Print "ブックの数: "; Workbooks.Count
Debug.Print "ブック名: "; ActiveWorkbook.Name
Debug.Print "シートの数:"; Worksheets.Count
Debug.Print "シート名: "; ActiveSheet.Name
Application.Workbooks(1).Worksheets(“Sheet1”).Name。正直書くのがだるい。ということでオブジェクト名.Nameでいいのだ。by TAさん
オブジェクトを変数にセットするオブジェクト変数
VBAにはオブジェクト固有型と呼ばれる型がある。名前の通り、オブジェクトが型になっている。『Dim 〇〇 As オブジェクト』でオブジェクト固有型を変数名に定義する。
- Workbooks, Workbook
- Worksheet
- Range
そして、なぜわざわざオブジェクト変数と呼んで特別扱いするかと言うと、代入の仕方がこれまでと違うから。
Set宣言を使用することで、オブジェクトをダイレクトに型宣言しながら変数に代入することができる。
Set 変数名 = オブジェクト
Dim wb As Workbook: Set wb = ThisWorkbook
Debug.Print "ブック名: "; wb.name
さらにwithステートメントを使用することで、オブジェクトを省略できるブロックを作ることができる。
With オブジェクト
.メンバー
End With
For Each In~Next文
書き方はこう。
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
Debug.Print ws.Name ‘Sheet1, Sheet2...
Next ws
だんだん分かってきたけど、アクティブなオブジェクトを指定した書き方になってないか、VBAは省略が結構できるから予期せぬエラーを発生させてしまいそう。カッコつけずにちゃんと狙ったオブジェクトを明記するのも大切なスキルのような気がする。
まとめ
だんだん難しくなってきました。。。普段からコードを書いてないと記憶の定着できてないことが沢山あります。。。ピラニアできない課題が出てきた。。。く、苦しい。。。💦とりあえず宿題が全部提出できて良かった!次はいよいよラストパート。