参照元に参照先の通し行番号を書き込む(1)

参照元に参照先の通し行番号を書き込む(1)

Wordの本文中で、参照箇所を明示したいときがある。段落番号とか見出しだったら、「相互参照」機能を使って文中に挿入できて、変更にも追随してくれるから良いのだが、通し行番号だけは、どうにもやり方がわからなかった。(もし「標準機能にあるで!」というのがあれば教えろ教えてください。)

行番号の参照などというものは、常に揺れ動くものなので、手動で管理するのは死ぬほどめんどくさいし、絶対に修正漏れが起こる。そこで、「ブックマーク」機能を使って解消することを考えた。

基本的には前回

akashi-keirin.hatenablog.com

までの続きです。

Bookmarkオブジェクトを使う

考え方

「ブックマーク」という機能を使えば、文書中の任意の場所に名前を付けることができる。VBAでは、Bookmarkオブジェクトを操作することによって、「ブックマーク」機能を使うことができる。

そこで、次のように考えた。

  • 参照先の箇所にブックマークを設定する
  • 参照元の「○行目」の行番号の部分(「○」の部分。)にブックマークを設定する
  • 前回作成したFunctionを用いて、参照先の通し行番号を取得する
  • 取得した行番号を文字列型に変換して「○」の部分に上書きする

こんな感じ。

ブックマークの設定

とりあえず、今回は手動で設定する。

まずは参照先。

f:id:akashi_keirin:20200601080004j:plain

このように、64行目の先頭に「参照先01」というブックマークを設定。

次に参照元

f:id:akashi_keirin:20200601080008j:plain

このように、「○行目」の「○」の部分に「参照元01」というブックマークを設定。

以上。

ブックマークした箇所(Rangeオブジェクト)の取得

まず、上記で設定したブックマークについて、Bookmarkオブジェクトを取得する方法。

これは、まずDocumentオブジェクトのBookmarksプロパティを参照してBookmarksコレクションを取得する。

んで、あとはItemメソッドのインデックスに取得したいブックマークの名前を指定すれば良い。

Itemは省略できるので、実際の書き方は

Document.Bookmarks("[ブックマーク名]")

になる。

Bookmarkオブジェクトが取得できれば、あとはそのRangeプロパティを参照すれば、ブックマークした箇所のRangeオブジェクトが取得できる。実に簡単。

参照元の文字を行番号に置き換える

参照元の「○」の部分をRangeオブジェクトとして取得しているのだから、あとはそのTextプロパティを書き換えたら良い。

楽勝!

コード

参照元に参照先の通し番号を挿入するコードは次の通り。

処理の中で、前回作成したgetLineNumberメソッドを呼び出しているので、そのコード(標準モジュールLineNumUtilに記載。)も再掲する。

リスト1 標準モジュール ModuleMain
Private Sub test00()
  Dim Doc As Document
  Set Doc = Application.ActiveDocument
  '参照元のブックマークオブジェクトを取得'
  Dim bm As Bookmark
  Set bm = Doc.Bookmarks("参照元01")
  '参照先ブックマークの通し行位置を取得'
  Dim lineNum As Long
  lineNum = LineNumUtil.getLineNumber(Doc.Bookmarks("参照先01").Range)
  '参照元のテキストを書き換える'
  bm.Range.Text = CStr(lineNum)
End Sub
スト2 標準モジュール LineNumUtil
Public Function getLineNumber( _
            ByVal tgtRange As Range) As Long
  Dim ret As Long
  'tgtRangeのあるページ番号を取得'
  Dim currPage As Long
  currPage = tgtRange.Information(wdActiveEndPageNumber)
  'tgtRangeのあるページ内での行番号を取得'
  Dim currLine As Long
  currLine = tgtRange.Information(wdFirstCharacterLineNumber)
  'tgtRangeが1ページ目にあるときは、その行番号を返す'
  If currPage = 1 Then
    ret = currLine
    GoTo Finalizer:
  End If
  '2ページ以上ある時は、手前のページまでの累計を足さなければいけない'
  Dim Doc As Document
  Set Doc = tgtRange.Parent
  'カーソル位置を記録'
  Dim orgRange As Range
  Set orgRange = Selection.Range
  '文書の先頭にカーソルを置く'
  Call Doc.Range(0, 0).Select
  '1ページ目の最終位置を取得'
  Dim pageEnd As Long
  '1ページ目の最終位置を選択'
  Dim i As Long
  For i = 1 To currPage - 1
    pageEnd = Doc.Bookmarks("\Page").End
    Call Doc.Range(pageEnd - 1, pageEnd - 1).Select
    ret = ret + Selection.Range.Information(wdFirstCharacterLineNumber)
    '次のページの先頭へ'
    Call Selection.MoveRight(wdCharacter, 1, wdMove)
  Next
  ret = ret + currLine
  'カーソル位置を戻す'
  Call orgRange.Select
Finalizer:
  getLineNumber = ret
End Function

例によって細かくコメントを入れたので、説明は省略。

うむ。これで盤石のはずだ!

使ってみる

リスト1を実行すると、

f:id:akashi_keirin:20200601080011j:plain

ウホッ! 完璧!

こんどは、

f:id:akashi_keirin:20200601080014j:plain

こんなふうにテキトーに参照先の位置をズレータにしておいて、再度実行!

f:id:akashi_keirin:20200601080017j:plain

な・・・・なんだってーーー!?

キ、キバヤシ……。これは一体どういうことなんだよ……。

あふれる涙を抑えながら「ブックマーク」を調べると、

f:id:akashi_keirin:20200601080020j:plain

なんと、テキストを書き換えたブックマーク(参照元01)が消えとる……orz

おわりに

どうも間違えてロンしてしまったか、フリテンだったようだ。

もう一工夫必要だということだ。

WordVBAはおれを甘やかしてくれぬ……。

で、今回の教訓。

BookmarkオブジェクトのRange.Textを書き換えるとBookmarkオブジェクトは消滅する。

覚えておこう。