やっぱり印刷もVBAでしたい
以前の記事で、差し込み印刷の機能のうち、VBAで差し込み印刷のデータのリンクを設定する方法を紹介しました。でも、そこまでやったら、印刷も自動処理させたいというのが人情というもの。印刷対象のフィルタリングと印刷処理のサンプルスクリプトを提示します。
動作確認環境
以前の記事と、まったく同じです。
WindowsXP
Microsoft Word 2002 SP3
Microsoft Excel 2002 SP3
差し込み印刷の設定がされたWordファイル名「D:\連絡文.doc」
差し込み印刷の元データが入力されたExcelファイル名「D:\MailMergeTest.xls」
差し込み印刷の元データが入力されたExcelのシート名「住所録」
エクセルのワークシートに入力された項目はこんな感じです。
今回は、データアクセスの設定はすでに済んでいるという前提で、差し込み印刷を実行するWordファイルの標準モジュールに記述するスクリプトを提示します。
抽出条件の変更
OpenDataSource実行時に設定するのが基本かな
VBAで処理するのですから、抽出条件はデータアクセスの設定の時、すなわちOpenDataSourceメソッドを実行する時のSQLSTATEMENT引数で指定するのがスマートなのです。しかし、場合によっては差し込み印刷設定後(OpenDataSourceメソッド実行後)にフィルタリングやソートなど、抽出条件を変えたい時もあるかもしれません。
いや、それでも抽出条件を変えるたびにOpenDataSourceメソッドを実行したっていいと思うのですが。
ま、しかしながらWordのメニューから操作していることが、VBAではどのように実現されるかってのは興味のあるところです。
データ絞込みの操作
通常の操作では、差し込み印刷のデータリンク設定は、ExcelのWorksheetやAccessのTable、クエリに対してなされるので、印刷対象の絞込みは後ですることになります。
具体的には、差し込み印刷ツールバーの「差し込み印刷の宛先」ボタンをクリックして表示される、「差し込み印刷の宛先」ダイアログで設定します。ここでは、列の条件を指定して絞込みをした後、行毎に処理対象にするかどうか決定できます。
また、印刷する時には「プリンタに差し込み」、新規文書に差し込む時には「新規文書への差し込み」ダイアログで処理対象範囲を指定できます。
以下では、これらの操作をVBAで実現する方法と、技術的な注意点を示します。
差し込み印刷のフィルタとソート
性別が「男」のデータを抽出して、金額を降順に並べ替える
VBAでDataSourceオブジェクトのQueryStringプロパティに抽出条件を指定します。
サンプルスクリプト
Sub MMFilter() '抽出条件の変更 Dim myMM As MailMerge Set myMM = ThisDocument.MailMerge myMM.DataSource.QueryString = "SELECT * FROM `住所録$` WHERE `性別` = '男' ORDER BY `金額` DESC" Set myMM = Nothing End Sub
差し込み印刷の宛先ダイアログを確認すると、条件が反映されています。
絞込み・抽出や並べ替え・ソートの条件は、DataSourceオブジェクトのQueryStringプロパティにSQLを設定することで実現します。
VBAで差し込み印刷の処理対象を指定
差し込み印刷の宛先ダイアログでは、行の左側にあるチェックボックスで処理対象を指定できます。
先ほどは、データの抽出で「男」を指定しましたが、今度は個別に指定します。
サンプルスクリプト
「男」を除外
Sub MMInc() '印刷対象の指定 'RecordCountプロパティが使えなくても可 Dim myMM As MailMerge Dim Cnt As Long Cnt = 0 Set myMM = ThisDocument.MailMerge With myMM.DataSource .ActiveRecord = wdFirstDataSourceRecord Do Cnt = Cnt + 1 If .DataFields("性別") = "男" Then .Included = False End If .ActiveRecord = wdNextDataSourceRecord Loop Until Cnt >= .ActiveRecord .ActiveRecord = wdFirstRecord End With Set myMM = Nothing End Sub
差し込み印刷の宛先ダイアログを確認すると、「男」だけチェックボックスがオフになってます。
VBAでプリンタに差し込み
最後に、データレコード番号が2から5までのものをプリンタに差し込みます。
Sub MMtoPrinter() Dim myMM As MailMerge Dim Cnt As Long Set myMM = ThisDocument.MailMerge With myMM .SuppressBlankLines = True .DataSource.FirstRecord = 2 .DataSource.LastRecord = 5 .Destination = wdSendToPrinter .Execute End With Set myMM = Nothing End Sub
MailMergeオブジェクトのSuppressBlankLinesにTrueを設定すると、空白の差し込みフィールドがある場合、空白行は印刷されません。空白行も印刷したい場合はFalseを設定。初期値は”True”。
DataSourceオブジェクトのFirstRecordプロパティに印刷開始のレコード番号、LastRecordプロパティに印刷修了のレコード番号を設定した後、MailMergeオブジェクトのExecuteメソッドを実行。
新規文書へ差し込むには、DestinationプロパティにwdSendToNewDocumentを設定します。
元の状態に戻すには
抽出条件をなくし、全てを選択対象にし、印刷範囲も全てのレコードにします。
さらに、空白行は印刷しないようにして、差し込み先をプリンタにします。
サンプルスクリプト
Sub MMreset() Dim myMM As MailMerge Set myMM = ThisDocument.MailMerge With myMM.DataSource .QueryString = "SELECT * FROM `住所録$`" .FirstRecord = 1 .LastRecord = -16 'レコードの印刷「全て」 .SetAllIncludedFlags Included:=True .ActiveRecord = wdFirstDataSourceRecord End With With myMM .SuppressBlankLines = True .Destination = wdSendToPrinter End With Set myMM = Nothing End Sub
QueryStringプロパティは、それぞれお好みに設定してください。
技術的なあれこれ
差し込み印刷の宛先ダイアログ
ネタバラシ的な話です。
差し込み印刷対象のレコードにフィルタをかけたり並べ替えをする時は、差し込み印刷の宛先ダイアログで設定するのですが、どのオブジェクトの設定が変わっているかを知りたい時にどうするかということ。最初にVBEのオブジェクトブラウザで、オブジェクトやらプロパティやらあたりをつけて、ヘルプを参照します。それでもどうにもよく分からない時は、コードの適当なところにブレークポイントを設定しておいて、ローカルウィンドウを通してプロパティの値の変化を見てみます。今回は、MailMergeのDataSourceオブジェクトに狙いをつけました。ま、他にはないでしょうね。
まず、フィルタの設定をしていない場合
ローカルウィンドウでMailMergeのDataSourceオブジェクトの値を確認します。データ接続の種類は標準のODSOです。
つぎに、差し込み印刷の宛先ダイアログでフィルタをかけます。性別が「男」のレコードだけを抽出します。
再度、ローカルウィンドウを覗くと、QueryStringプロパティとTableNameプロパティのSQLにWHERE句が付加されている!ついでに、RecordCountも6になってます。
さらに、「金額」を降順に並び替えると、
ORDER BY 句が付け加わる。
これで、差し込み印刷設定後のフィルタリングとソートはQueryStringプロパティを変更することで実現しているらしいことが分かりました。こういったことは、いろいろな方法がありますが、ローカルウィンドウやウォッチウィンドウを使うのはオーソドックスな方法だと思います。
TableNameプロパティとQueryStringプロパティ
TableNameプロパティは、ヘルプによると
差し込み印刷文書に添付されたデータ ファイルからレコードを取得するために使用する SQL クエリにより、文字列型 (String) の値で取得します。テーブル名が不明な場合、または現在のデータ ファイルに適していない場合、このプロパティは空になることがあります。値の取得のみ可能です。
ということなので、TableNameプロパティを直接変更することはできません。
オンラインのヘルプだと、少し表記がちがっていて、
差し込み印刷文書に結合されたデータ ファイルからレコードを検索するときに使用される SQL クエリを示す文字列型 (String) の値を取得します。テーブル名が不明な場合、または現在のデータ ファイルに該当しない場合は空白になります。
と書いてあります。
QueryStringプロパティはというと
差し込みデータ ファイルのデータのサブセットを検索するときに使用するクエリ文字列 (SQL ステートメント) を設定します。値の取得および設定が可能です。文字列型 (String) の値を使用します。
値の設定が可能。「データのサブセットを検索するときに使用するクエリ文字列」って、分かりにくいな。きっと、「差し込まれたデータの抽出や並べ替え」ってことなんでしょう。
参考 MailMergeDataSource メンバ(Microsoft ライブラリ)
SQLでワークシートを指定するときの記述方法
以前の記事にも書きましたが、
[HOWTO] Visual Basic または VBA から ADO を Excel データで使用する(http://support.microsoft.com/kb/257819/ja)
にあるように、原則的には角かっこの使用を推奨しているようです。
例えば、こんなふうに。
myMM.DataSource.QueryString = "SELECT * FROM [住所録$] WHERE [性別] = '男' ORDER BY [金額] DESC"
しかし、上記で分かるようにWordが自動で設定するQueryStringはキーボードのチルダ (~) の下にある (日本語キーボードの場合は P キーの右横にある) 斜めの単一引用符を使用しています。
myMM.DataSource.QueryString = "SELECT * FROM `住所録$` WHERE `性別` = '男' ORDER BY `金額` DESC"
角かっこを使っても動くのですが、「差し込み印刷の宛先ダイアログ」の表示に不具合が出ます。
角かっこを使用したSQLで「性別」が男のレコードを抽出して、「金額」を降順に並べ替えると、次のようになります。
抽出結果はいいのですが、差し込み印刷の宛先ダイアログの性別の矢印がハイライトになりません。また、フィルタと並べ替えに、条件が表示されません。
新しいバージョンのWordでは修正されているかもしれません。どうなんでしょ。
RecordCountプロパティとIncludedプロパティ
データのフィルタ後、個別にレコードの対象を決定するには、Includedプロパティを使います。IncludedプロパティにTrueを設定すると、差し込み印刷の宛先ダイアログのチェックボックスがOnに、Falseを設定するとOffになります。
Includedプロパティのヘルプには、条件によってTrue/Falseを設定する以下のサンプルが載っています。
Sub CheckRecords() Dim intCount As Integer On Error Resume Next With ActiveDocument.MailMerge.DataSource 'データ ファイルの最初のレコードを作業中のレコードに設定します。 .ActiveRecord = wdFirstRecord Do intCount = intCount + 1 'フィールド番号 6 の値を 5 桁以上かどうかチェックします。 If Len(.DataFields(6).Value) < 5 Then 'フィールド番号 6 の値が 5 桁未満の場合、そのレコードを除外します。 .Included = False 'そのレコードを無効な住所とします。 .InvalidAddress = True 'レコードが差し込み印刷から除外された理由を説明したコメントを指定します。 .InvalidComments = "レコードの郵便番号が 5 桁未満なので、" & _ & "差し込み印刷から除外します。" End If 'データ ファイルの次のレコードに移動します。 .ActiveRecord = wdNextRecord 'カウンタ変数がデータ ファイルのレコード数と等しい場合、ループを終了します。 Loop Until intCount = .RecordCount End With End Sub
このサンプルは、レコード数にRecordCount、ActiveRecordプロパティにwdNextRecordを使っているところに難があります。
以前の記事でも少し触れたように、私の経験ではExcelのワークシートにODBCもしくはDDE接続した時、またはAccessのクエリに接続した時には、RecordCountプロパティは”-1″となり、レコード数が取得できません。
また、ActiveRecordプロパティにはデータレコード番号、またはWdMailMergeActiveRecordクラスの定数のいずれかを設定できて、wdNextRecordは「結果セットの次のレコード」を表します。結果セットの次のレコードなので、フィルタ設定で除外されたレコードはスキップされます。
新しく設定するたびに、SetAllIncludedFlagsメソッドを使うなどして管理できればいいのですが、ここは多少無駄があってもwdNextDataSourceRecord定数(データ ファイルの次のレコード)を使って、全てのレコードに処理を施したほうが無難だと思います。
全てのレコードを印刷する時のLastRecordプロパティ
全てのレコードを印刷する時は、MailMergeオブジェクトにExecuteメソッドを実行する前に、DataSourceオブジェクトのFirstRecordプロパティに”1″、LastRecordプロパティに”-16″を設定します。
これも、ヘルプなどには載っていないようですが、FirstRecordとLastRecordプロパティの初期設定がこのようになっています。
最近のコメント