【連載】差し込み印刷のレコードごとにドキュメントを作成するマクロの解説(第5回)

第5回 1ページ目を削除する

前回

akashi-keirin.hatenablog.com

新規文書作成後にできる余分なセクション区切りの削除まで進みました。

今回は、コマンドボタンを置くためにのみ存在していた1ページ目の削除を行います。

目次

〝ページを削除する〟とは?

Wordにおいて、文書の部分を削除するには、その部分を表すRangeオブジェクトを削除するという方法を用います。

セクションを削除したければ、まずSectionオブジェクトを取得し、そのRangeプロパティを叩いてそのセクションの範囲を表すRangeオブジェクトを取得してからDeleteメソッドで削除します。

' アクティブドキュメントの2つ目のセクションを削除
Dim doc As Document
Set doc = ActiveDocument
Dim sect As Section
Set sect = doc.Sections.Item(2)
Call sect.Range.Delete

段落を削除したければ、まずParagraphオブジェクトを取得し、そのRangeプロパティを叩いてその段落の範囲を表すRangeオブジェクトを取得してからDeleteメソッドで削除します。

' アクティブドキュメントの3つ目の段落を削除
Dim doc As Document
Set doc = ActiveDocument
Dim para As Paragraph
Set para = doc.Paragraphs.Item(3)
Call para.Range.Delete

したがって、文書の1ページ目を削除したければ、

文書の1ページ目を表すRangeオブジェクトを取得して、そのDeleteメソッドを使えば良い

ということになります。

ところがここで難問に出くわします……。

Wordには〝ページ〟を表すオブジェクトがない

という問題です。

〝ページ〟を表すオブジェクトがない

これは、かなり我々の実感に反する実装です。

文書に〝ページ〟という単位があるのは当たり前のように感ずるからです。

ただ、落ち着いてよく考えると、〝ページ〟という単位は実に不安定な単位であることがわかります。

文書の中で、個々の〝ページ〟には確たる境目というものがありません。

この点がセクションや段落、文字とは異なります。

セクションなら、あるセクションと別のセクションの境目には必ずセクション区切りがあります。

段落なら、ある段落と別の段落の境目には必ず改段落マークがあります。

一方、ページの場合、ページと別のページの間にページ区切りが必ずしも存在するわけではありません。

任意の位置にページ区切りを入れることもできますが、基本的に、あるページと別のページの境目は、ページ設定の都合でたまたまそうなっているだけに過ぎないのです。

このような事情で、Wordには〝ページを表すオブジェクト〟が存在しないのでしょう。やはり、理にかなった設計であると思います。

とはいえ、〝特定のページ全体(を表すRangeオブジェクト)を取得したい〟という場面はそれなりにあることでしょう。

このような場合には、Wordの組み込みブックマークという機能を用います。

〝1ページ目〟のRangeオブジェクト取得・削除

〝定義済みのブックマーク〟とは?

まず、「ブックマーク」とは、文書の任意の範囲に名前を付ける機能だと思えば良いでしょう。

これは、ちょうど、Excelの「名前」機能に似ています。

Excelで、任意のセル範囲に名前を付けて参照することができるように、Wordでも「ブックマーク」という機能によって、文書内の任意の範囲に名前を付け、その名前によって当該範囲を参照することができます。

このように、「ブックマーク」は基本的にはユーザが好きなように設定するものですが、始めから定義されているブックマークがあります。それが今回使用する定義済みのブックマーク(Predefined Bookmarks)です。

「定義済みのブックマーク」はけっこうたくさんありますので、コチラでご確認ください。(日本語版のページだと、自動翻訳のせいで翻訳してはいけないところまで日本語になってしまってイマイチなので、英語版のURLをご案内します。慣れたらむしろ日本語版より読みやすいかも……。)

数ある「定義済みのブックマーク」の中で、今回使用するのは\Pageです。

Current page, including the break at the end of the page, if any. The current page contains the insertion point. If the current selection contains more than one page, the "\Page" bookmark is the first page of the selection. Note that if the insertion point or selection is in the last page of the document, the "\Page" bookmark does not include the final paragraph mark.

この説明にあるように、\Pageというブックマークは、

  • カーソル(insertion point)のあるページの範囲で、
  • 末尾にページ区切りがあるときはページ区切りを含み、
  • 選択範囲が複数ページにわたる場合は選択範囲内の先頭のページの範囲で、
  • カーソル(insertion point)が文書の最終ページにあるときは、末尾の改段落マークを含まない

という範囲のRangeオブジェクトを表すわけです。

……ということは、文書の1ページ目を取得するには、

文書の先頭にカーソル(insertion point)を置いて、「定義済みのブックマーク」/Pageを取得すれば良い

ということです。

文書の1ページ目を取得する

では、「定義済みのブックマーク」のしくみを用いて文書の1ページ目を表すRangeオブジェクトを取得します。手順は次のとおりです。

  1. 文書の1ページ目を表すBookmarkオブジェクトを取得する
  2. BookmarkオブジェクトのRangeプロパティを叩いて文書の1ページ目を表すRaneオブジェクトを取得する

これだけです。

リスト1
ソースコードを
Private Sub ExportMailMergeDocuments()
    Dim doc As Document
    Set doc = ThisDocument
    Dim mm As MailMerge
    Set mm = doc.MailMerge
    mm.Destination = wdSendToNewDocument
    mm.SuppressBlankLines = True
    Dim mds As MailMergeDataSource
    Set mds = mm.DataSource
    mds.ActiveRecord = 1
    mds.FirstRecord = 1
    mds.LastRecord = 1
    Call mm.Execute( _
        Pause:=True _
    )
    Dim newDoc As Document
    Set newDoc = Application.ActiveDocument
    Dim lastSect As Section
    Set lastSect = newDoc.Sections(newDoc.Sections.Count)
    If lastSect.Range.Start = newDoc.Content.End - 1 Then
        Call lastSect.Range.Previous(Unit:=wdCharacter, Count:=1).Delete
    End If
    ' 念のためカーソルを文書の先頭に置く
    Call newDoc.Range(0, 0).Select
    ' 先頭ページを表す`Range`オブジェクトを取得する
    Dim firstPageRng As Range
    Set firstPageRng = newDoc.Bookmarks.Item("\Page").Range
End Sub
        

新規文書作成直後、カーソル(insertion point)は文書の先頭にあるはずですが、念のため

Call newDoc.Range(0, 0).Select

によって明示的に(explicit)カーソル(insertion point)を文書先頭位置に置いています。

DocumentオブジェクトのRangeメソッドの引数は、[Document].Range(start, end)となっています。

引数startendは、ともに文書内の絶対位置を表す数値で、

newDoc.Range(0, 0)

ならば、文書の0文字目から0文字目の位置、すなわち文書の先頭の位置を表すRangeオブジェクトが返ることになります。

文書の先頭位置を表すRangeオブジェクトのSelectメソッドを実行することによって、文書の先頭にカーソル(insertion point)を置いているわけです。

さて、文書の先頭位置にカーソル(insertion point)がある状態で「定義済みのブックマーク」\Pageを取得すれば、そのブックマークは1ページ目全体を指し示すはずなので、

newDoc.Bookmarks.Item("\Page")

で1ページ目全体Bookmarkオブジェクトを取得し、

newDoc.Bookmarks.Item("\Page").Range

Rangeプロパティを叩いて返されるRangeオブジェクトを変数firstPageRngに突っ込んでいます。

1ページ目全体を表すRangeオブジェクトを削除する

こうなると、あとは取得したRangeオブジェクトのDeleteメソッドを実行して削除するだけです。

リスト2
ソースコードを
Private Sub ExportMailMergeDocuments()
    Dim doc As Document
    Set doc = ThisDocument
    Dim mm As MailMerge
    Set mm = doc.MailMerge
    mm.Destination = wdSendToNewDocument
    mm.SuppressBlankLines = True
    Dim mds As MailMergeDataSource
    Set mds = mm.DataSource
    mds.ActiveRecord = 1
    mds.FirstRecord = 1
    mds.LastRecord = 1
    Call mm.Execute( _
        Pause:=True _
    )
    Dim newDoc As Document
    Set newDoc = Application.ActiveDocument
    Dim lastSect As Section
    Set lastSect = newDoc.Sections(newDoc.Sections.Count)
    If lastSect.Range.Start = newDoc.Content.End - 1 Then
        Call lastSect.Range.Previous(Unit:=wdCharacter, Count:=1).Delete
    End If
    ' 念のためカーソルを文書の先頭に置く
    Call newDoc.Range(0, 0).Select
    ' 先頭ページを表す`Range`オブジェクトを取得する
    Dim firstPageRng As Range
    Set firstPageRng = newDoc.Bookmarks.Item("\Page").Range
    ' `Range`オブジェクトを削除する
    Call firstPageRng.Delete
End Sub
        
Call firstPageRng.Delete

で1ページ目を削除します。

Deleteメソッド実行直後

画像では実にわかりづらいのですが、1ページ目がめでたく削除されています。

おわりに

これで、〝データ(笑)を差し込んだ新規文書〟が完成しました。

次回は、この整形済み新規文書に名前を付けて保存する処理を解説します。

関連記事

akashi-keirin.hatenablog.com

akashi-keirin.hatenablog.com

押すなよ! 絶対押すなよ!