ふんわりした生活

本を読んだり仕事でやってみたことなどの日常から、ふんわりと気づきなどを書いていきます

もしも3日間のうちにVBAでツールをつくれるようにしなければならないとしたら

何を教えるべきか、というお話です。イメージするとしたら、月曜日から教えはじめて木曜日、金曜日で最初のツールをひとつ完成させるという感じ。 もうこれ以上、メンテナンスできないクソマクロを増やさないで!!と強く願う方もいらっしゃると思いますが、ここはそういうことを置いておこうと思います。ごめんなさい。

実際のところ、勘の良い方であれば3日もかからないと思います。簡易的な電卓みたいなものならプログラミング初心者でも同じくらいでつくることができるのではないかと思います。ですが、正直言ってVBAは覚えることが多すぎると思っています。だから覚えるだけで一苦労、なんだよ構文エラーって・・・さらに配布後のメンテナンスも非常に面倒です。

WordやPowerPointだと、見た目を制御するためにはそこそこコードを書く必要があります。ExcelAccessはデータの塊を表現したソフトウェアなので、軽く数行のコードだけで動くものができてしまう、というところが長所であり短所でもあります。とかなんとかダラダラと書いていくのもアレですので、もしも3日間でつくれるようにしなければならないとしたらというお話に移ります。

初日

まずはどのOfficeソフトウェアを選択するか、というところから始まります。ですが、ここはもちろんExcel一択です。たいていの場合、WordやPowerPointを自動化したいと思うことは少ないでしょう。なんらかのデータが大量にあるいは高頻度で存在していて、「この山をどうにかさばきたい」というのがモチベーションであることが多いはずです。ですからExcelを使います。古いVistaくらいのPC(もうすぐサポート終了ですね)でも国内大手メーカーさんのものだとPersonal Edition(WordとExcelだけ入っている)というOfficeがプリインストールされていたと思います。

1時間目

ということでExcelを起動してもらうことになるのですが、次にやるのはVBEの起動です。Visual Basic Editorですね。AltキーとファンクションキーF11を同時に押すことで起動してきます。そうしたらざっくりと画面の説明をします。画面左上のプロジェクトエクスプローラ、その下のプロパティダイアログ、画面中央のエディタ領域、その下のイミディエイトウィンドウです。それぞれの役割を簡単に説明したら、次は動かしてみるためにサブプロシージャの大枠だけ書いてもらいます。こんな感じに。

Sub macro()

End Sub

ここはサブプロシージャの名前以外ほとんど自動で書いてくれることを体感してもらって、なんだ、大したことねぇな、ビビらせやがってと思ってもらうのが第一です。そうしたら次はMsgBox関数をつかってメッセージダイアログを表示させてもらいます。ここで苦手意識が発生しないように注意します。そうしないと、このあとの説明が大いに時間を要することになるうえ、理解も進まなくなるためです。

MsgBox関数で何かを表示させることができたら、続いてDebug.Printメソッドでイミディエイトウィンドウに何かを表示させます。マクロが動作しているときにどんなことが起きているか、を知ろうとすることになるので軽く説明しておきます。いわゆるHello World的なものですね。

2時間目

たいていの企業では、この2時間目を初日に確保するのは非常に困難だと思われます。というのも、ただでさえ時間外労働を強いられるのにこんな時間を確保できるとは考えにくいからです。ですが、ここでは確保できたとして話を進めます。そうしないと話が進まないので…

この時間では、構文そのものを学んでもらうのではなくあらかじめ用意した形をコピペしてもらうようにします。たとえば、データをいったんどこかへ置いておきたい!となったら変数の出番です。しかしどのように宣言すべきか?という説明をしていたのでは時間が足りません。そこで、これをコピペして名前だけ変えようというようにします。ひどいですね。

Dim 変数名

データ型はどうした!?と驚く方もいらっしゃるかと思いますが、最初はあまり厳密にせずに完成できるようになるところまでを説明して身に着けてもらいます。そのため、そうしたこともこの時点では省略していきます。JavaScriptPHPrubyでもデータ型は明示してない(もしくはできない)ことが多いですよね。

これらコピペを駆使してなんとか1から10までをイミディエイトウィンドウに出力したり、3の倍数のときだけ別のものをイミディエイトウィンドウに出力したりするところまでいきます。パーツを組み合わせるイメージです。

3時間目

もはやここまでくると、かなり教育熱心な企業でしか耐えられないかもしれません。大手企業の新入社員教育とかでなければ確保できないかな?3時間目では2時間目までの「コピペ駆使」を使って、演習をします。2時間目にやったものと同じサブプロシージャを名前を変更して自分で写経して実行するとか、コード中に「10」とか数値を直接書いてあるところをほかの数値に変えてみるとかです。

正直言うと、この演習の時間が取れるかどうかでつくれるようになるかどうかが決まるでしょう。コピペでも一度以上、その組み合わせに出会っていなければすぐにその組み合わせをして問題を解決しようということになりません。結果として時間ばかりが過ぎていくことになります。そこで、この演習では組み合わせを変えてみたり条件を変えてみて何度も繰り返し実行することがポイントになります。

Sub macro()
  Dim count
  For count = 1 To 10
      Debug.Print count
  Next
End Sub

こういう断片でも動くものを形を変えて何度もやると、「条件をわけるときはこう」「くり返すときはこう」というのが見えてきます。

二日目

二日目になると、2つのことをできるようになる必要があります。それは、

  1. シートからデータを取り出す、セットする
  2. ブックを開く、保存する

ここもコピペでパーツを組み合わせる練習を繰り返します。これらを行うために避けて通れないことが、オブジェクトを変数に格納することです。

Dim sheet
Set sheet = ThisWorkbook.Worksheets(1)

このあたりでどれがオブジェクトの変数なのかわからなくなってくると思うので、データ型についてよく使うものを中心に説明します。最低でも次のものだけ練習しておくといいでしょう。

  • Integer
  • Long
  • String
  • Double
  • Workbook
  • Worksheet
  • Range

そのほか、Withをつかってオブジェクトを操作することにも慣れておくといいでしょう。あまり高速でないイメージが勝手にありますが、オブジェクトをひとまとめに操作できるので便利かつわかりやすいですね。

With ThisWorkbook.Worksheets(1)
    .Name = "nalulabo"
    .Range("A1").Value = "1234"
End With

さらに、オブジェクト変数の「Empty」と「Nothing」「Null」についても理解が難しいので軽く押さえておくと後が楽になります。違いとしてはざっくり説明すると次のとおりです。

説明
Empty オブジェクト変数になにも詰め込まれていない状態
Nothing 「何もない」を表す特殊なオブジェクト
Null データのある場所がゼロ番地

Setステートメントを使っていない、宣言しただけのものはEmptyの状態になります。状態をチェックするには「IsEmpty」関数を使います。Nothingが詰め込まれているかどうかは変数がNothingかどうかを「Is」ステートメントで確認します。Nullかどうかは「IsNull」関数を使います。それぞれ値なのか、状態なのか、変数データのある場所なのかということで違っているので混乱しやすいですね。

Public Sub macro()
    Dim aaa
    Set aaa = Nothing
    If IsEmpty(aaa) Then
        Debug.Print "empty"
    ElseIf IsNull(aaa) Then
        Debug.Print "null"
    ElseIf aaa Is Nothing Then
        Debug.Print "nothing"
    End If        
End Sub

なお、オブジェクト変数にNullが詰め込まれるにはSetステートメントを使わずにVariant型の変数へ代入するしかないので、EmptyかNothingかをチェックすると十分でしょう。

1時間目

シートの操作を簡単に説明する時間にあてます。シートの特定の仕方を4種類説明することから始めます。シートは(1)Worksheetsコレクション(Excelを見ながらタブを示して)を順番に探す方法、(2)アクティブになっているシートを使う方法、(3)シートオブジェクトを利用して特定する方法、(4)Worksheetsコレクションからシート名で特定する方法です。

それぞれ一長一短ありますのでざっくりとだけ説明します。

No. 方法 メリット デメリット
1 Worksheetsコレクションから順番で 操作対象が左から何番目かわかれば簡単 シートの並びが変わると対象が変わってしまう
2 アクティブになっているシートで ActiveSheetオブジェクトでサクッと利用できる 選択されたシートが変わると対象が変わってしまう
3 シートオブジェクトで 狙ったシートを直接利用できる 新規追加したものはオブジェクト名がわからない
4 Worksheetsコレクションからシート名で シート名がわかれば直感的 シート名が変更されると見つけることができない

どのように操作したいかで方法を選択するとよいでしょう。

また、セルの参照方法としてはRangeオブジェクトのみになります。Cellsコレクションなどを使っても結果的にRangeオブジェクトが返されるのでRangeオブジェクトをつかうと間違いないです。また、省略できる標準プロパティというのがあって「.Value」を省略していることがありますが、ややこしいので省略しないほうがクソマクロになりにくいでしょう。

2時間目

2時間目はブック操作です。別のブックを開く、新規でブックを作成する、ブックの変更を破棄して閉じる、ブックを保存するといったところです。ブックは開いたり新規に追加するとWorkbookオブジェクトが返されるので、オブジェクト変数へ詰め込むかWithステートメントブロックで操作するようになります。Withのほうが便利ですが、どうしてもほかのブックも同時に操作する必要があることもケースとしてはあります。そのため、ブックもオブジェクト変数へ詰めておいたほうがわかりやすくなります。混乱するとブックもコードもぐちゃぐちゃになりますので。

ブックの変更を破棄して閉じるには、ブックのCloseメソッドにFalseを渡すと実現できます。つけない場合はファイル保存ダイアログが表示されるので、逆に確認してほしい場合はFalseを渡さないようにします。

ブックの保存はブックのSaveメソッドを使います。ほかにもCSVなど形式を指定して保存するSaveAsメソッドもありますので、PDFをつくって遊んでみるとよいでしょう。また、すでに同じ名前のブックがファイルとして存在するかどうかなどについても、ここでさらりと説明しておくといいですね。

3時間目

ここまで学習した内容をつかっていろいろ遊んでみるという演習をするとよいでしょう。質問を受け付けてセルの背景色を塗ったりフォントサイズを変えたり枠線をつけたりといったこともやってみると、より複雑な操作をすることができるようになります。また、複数のセルをもつある範囲から一気にデータだけを取り出す方法として配列を紹介してもいいですね。表の形にデータを整形してやることでワークシートとマクロの間で高速にデータのやりとりができるということも体験するといいでしょう。

このほか、セルやセルの範囲に名前を定義する(Excelのほうの)説明をすると、Rangeが非常に便利になることも説明できるとなおよいですね。行や列を頻繁に追加削除しても名前をつけておくと(名前を付けた範囲が削除されなければ、ですが)セル位置ではなく名前で参照できるようになります。

三日目

いよいよ最終日です。てんこ盛りに詰め込んだので完全に消化不良だと思いますが、ここからは応用というかツールとして完成させることができるようになるための仕上げの話です。

マクロの実行をユーザーにどのように開始してもらうか、これを決める必要があります。方法はいろいろあるのですが、よくあるのはExcelの図形オブジェクトをペタッと貼ってマクロを登録するとかでしょう。こうした内容を簡単に説明して演習を行っていきます。 もしもアプリのようなフォームが必要である場合はフォームの説明をすることになりますが、ちょっとした操作にそこまでの準備が必要かどうかで後日の学習にするかを考えるとよいです。

だいたい、このあたりまで来ると書籍やウェブの情報を元に自分で学習していくことができるようになっているはずです。ここからは独学でもよいでしょう。

これは教えないのか、教えなくていいのか

3日間で3時間ずつしか確保できないとして、最低限だけを説明していくと上記のような感じになるのですが、それじゃあクソマクロ量産体制に入るだけだろうということはあるでしょう。たとえばスクリプトの分割です。1つのサブプロシージャで長々と書いていくと、自分でも読みづらくなります。他人はさらに読めない状況になります。そうしたときに分割が必要になります。しかし、最初から分割を意識させてしまうとプログラマでもない方には混乱のもとですので、そこは考えずに走り抜けてもらうことにするということです。ひととおり動くようになったあと、コードを読み返してもらい、意味のあるまとまりとしてコメントを入れていくと分割の仕方がわかりやすいのではないでしょうか。

このほか、関数もそうですね。サブプロシージャは値を返すことができませんが、関数は値を返すことができます。これまた使い方というか用途が理解できなければ混乱のもとなので避けました。クラス定義もそうです。

さらにテキストファイルの読み書きも普通のプログラミングでは学習しますが、Officeスイートを利用するという時点で対象もOfficeのことが多いです。そこでテキストファイルは独学の範囲にすることにしました。プログラマの方は3日間のどこかで学んだほうがいいですよ!もうひとつ、COMの利用もあります。プログラマの方は学習必須になると思いますが、こちらも同じ理由で除外しました。

もっと基本的なこととして、定数はどうした、というのもあるでしょう。あとから値を変更することができないものなので、コード中に直接書いてしまっている数値などはこれにするべきですよね。これはある程度の演習をしてからのほうが、定数という機能の効果をより理解できてよいと考えるます。もしどこかへ入れるとしたら三日目の演習時がよいでしょう。

おススメの書籍とかないのか

私自身もExcelマクロの入門書を電子書籍で出版しているのですが、正直申し上げておススメしたい書籍はありません。というのも、どれを買ってもらっても書いてあることはおおよそ同じだからです。よってもし購入を考えているのであれば、次のことを念頭に置いていただくと選びやすいと思います。

  1. 簡単なところから順番にやりたいか
  2. 辞書のように逆引きして「やりたいこと」から学びたいか
  3. 特定のある機能だけ学びたいか

もし上記1であれば、ブルーバックスだったかで出版されている入門書がよいでしょう。ほんとうに簡単なところから説明されているので、少しずつ時間をかけて学ぶにはとてもよいはずです。逆に上記2のように「何かしらつくりたいもの」があって、それをつくるために必要な事柄から、どうやって書いていけばよいかを学ぶのであれば逆引き辞典のような書籍を選ぶとよいです。また上記3のように、すでに何かつくったことがあって、その経験を補足・補強する目的であればVBAでは書籍を選ぶ必要はありません。MSDNなどMicrosoft社が公開しているドキュメントをお読みになるべきです。

最後に

思いのほか長文になってしまったことを深く反省しております。VBAは非常に便利でパワフルなツールです。おかげでPowerShellがイマイチ伸び悩んでいるような気がしなくはありません。

もしVBAのようにドキュメントと一緒になってしまって管理しにくいのが嫌だ!ということであればPowerShellはおススメです。 いろんなもの(プログラミング言語やツール)のキメラっぽいものですが、VBAを覚えてからであれば使い勝手の良いツールになると思います。

わたしはマクロよりもテキストファイルで動作するVBScriptのほうが好みで、10年以上前からそっちでばかりツールを書いていました。あまり画面があることにこだわっていなかったからかもしれません。VBScriptも昔はマルウェア用のツールというイメージもあったと思いますが、いまはPowerShellがその担当をしてくれています。VBSネタもまたエントリしてみようかな。

こんなのもあります。

note.mu