ToDo完了後に毎回リスト更新、メール送信――VBAでその手順、削減しませんか?:働く価値を上げる“VBA/GAS”術(13)(3/4 ページ)
「この作業が終わったら報告しないと」――しかし、毎回メールで報告するのは面倒くさい作業です。今回は、ToDo完了してリストを変更したら自動でメールが送信される仕組みを紹介します。
イベントとイベントプロシージャ
VBAの一部のオブジェクトには、固有の「イベント」が定義されています。例えば、「Workbook」オブジェクトであれば「ワークブックが開いた後」や「閉じる前」、「Worksheetk」オブジェクトであれば「ワークシートがアクティブになった後」や「削除される前」などといったタイミングがイベントとして定義されています。
これらのイベントをきっかけに動作するプロシージャをイベントプロシージャと呼びます。例として幾つかのイベントプロシージャを以下にリストアップしています。
動作 | イベントプロシージャ |
---|---|
ワークブックが開いた後 | Workbook_Open |
ワークブックが閉じる前 | Workbook_BeforeClose |
ワークシートが削除される前 | Worksheet_BeforeDelete |
ワークシートがアクティブになった後 | Worksheet_Activate |
ワークシートが変更された後 | Worksheet_Change |
イベントプロシージャは標準モジュールではなく、イベントの対象となるオブジェクトモジュールに記述します。Workbookオブジェクトのイベントプロシージャであれば「ブックモジュール」に、Worksheetオブジェクトのイベントプロシージャであれば「シートモジュール」に記述します。
WorksheetオブジェクトのChangeイベント
今回のToDo完了メール送信マクロでは、「ワークシートが変更された後」のイベントプロシージャを作成するので、シートモジュールに記述します。
VBE(Visual Basic Editor)のプロジェクトエクスプローラー内の「Sheet1(ToDo)」が対象のシートモジュールになるので、ダブルクリックして開きます。
コードウィンドウの上部に2つのプルダウンボックスが並んでいます。左側が「オブジェクトボックス」、右側が「プロシージャボックス」と言います。イベントプロシージャは、それぞれオブジェクトとプロシージャを選択することで、簡単に作成できます。
オブジェクトボックスから「Worksheet」、プロシージャボックスから「Change」を選択して、イベントプロシージャ「Worksheet_Change(ByVal Target As Range)」が挿入されることを確認しましょう。
「Target」というRange型の引数が与えられています。これは変更があったセル範囲が格納されます。イベントプロシージャ内で活用して、さまざまな処理を実現できます。
ListColumnオブジェクトのデータ範囲を取得する
まず、以下の部分に注目しましょう。
Set myRange = Sheet1.ListObjects(1).ListColumns("ステータス").DataBodyRange
ToDoリストはテーブル化されているので、「Sheet1.ListObjects(1)」にすることで、「ListObject」オブジェクトとして取得できます。続く、「ListColumns」プロパティで、「ListColumns」コレクションを取得します。
ListObjectオブジェクト.ListColumns
また「カラム名」を指定することで、コレクションから特定の「ListColumn」オブジェクトを取得しています。
ListColumnsコレクション(カラム名)
ListColumnは、テーブルの単体の列を表すオブジェクトで、カラム名はその見出しになります。従って、カラム名「ステータス」を指定して取り出したListColumnオブジェクトは、テーブル内のステータス列を表します。
さらに、「DataBodyRange」プロパティを使用しています。これはListColumnオブジェクト内のデータ範囲のみを「Range」オブジェクトで取得するプロパティです。
ListColumnオブジェクト.DataBodyRange
つまり、今回のToDoリストの見出しを除いて「E2:E4」のセル範囲を取得できます。
セル範囲にセルが含まれるか判定する
次に以下の部分を見ていきましょう。
Dim r As Range For Each r In Target If Not Intersect(myRange, r) Is Nothing And r.Value = "完了" Then Call ToDo完了メール送信(r.row) End If Next r
「For Each」ステートメントで、変更のあったセル範囲であるTarget内の個々のセルについて繰り返しを行います。その内部にあるIf文ですが、以下2点の判定の「And」をとっています。
- 現在対象となっているセルがmyRange、つまり「ステータス」列のデータ範囲内かどうか
- その値が「完了」かどうか
「Intersect」メソッドは「Application」オブジェクトのメンバーです。このメソッドは、引数で指定した複数の範囲の重なっている部分のセル範囲を返すメソッドです。
Intersect(セル範囲1, セル範囲2,...)
第1引数は「ステータス列のデータ範囲」を表す「myRange」。第2引数はTargetのうちの単体セルr。そのため、Intersectメソッドの戻り値や、条件式の判定値は以下のようになります。
- rがmyRangeに含まれている→戻り値はr→「Intersect(myRange, r) Is Nothing」はFalse→If Notで反転するとTrue
- rがmyRangeに含まれていない→戻り値はNothing→「Intersect(myRange, r) Is Nothing」はTrue→If Notで反転するとFalse
セルが「ステータス列のデータ範囲」に含まれ、かつその値が「完了」ならば、「Sub ToDo完了メール送信(ByVal row As Long)」を呼び出します。その際に、引数として、該当セルの行番号を渡します。
Outlookでメールを送信する
「Sub ToDo完了メール送信(ByVal row As Long)」の動作は、これまでの連載を読んでいる人なら、簡単に読み解けると思います。
今回は、Outlookでのメール送信を紹介します。メールを送信するには、「MailItem」オブジェクトに対して、各プロパティを設定した上で「Send」メソッドを使います。
MailItemオブジェクト.Send
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
- 「数百のファイルを1つ1つ開くの面倒……」、複数のExcelデータを1箇所に集約するマクロ術
経費精算書のように「バラバラのデータを1箇所に集約すること」は、多く発生する業務の1つです。しかし、1つ1つのファイルを開きコピー&ペーストするのは手間が掛かる業務。その業務を、マクロを使って自動化する方法を紹介します。 - 「計算式エラーで残業確定……」、GASで入力データのチェックツールを作成
1つのGoogleスプレッドシートを複数人で共同編集するとき、想定していた形式とは違うデータを入力されると、不備が発生してしまう場合があります。そのような問題を、GASで解決するにはどうすればいいのでしょうか。 - プログラム自動実行で仕事を楽に! APIでSlackなどと連携できる「Google Apps Script」とは
日頃発生する“面倒くさい業務”。簡単なプログラミングで効率化できる可能性がある。本稿では、Googleが提供する数々のアプリケーションを操作できる「Google Apps Script」を紹介する。※ショートカットキーの解説あり