カーソルを任意の場所に置くFunctionの改良(Word)

カーソルを任意の場所に置くFunctionの改良(Word)

似たような書類を、宛先別に大量生産するような場合に、差込印刷機能を使う場面は多いと思う。

で、差込印刷の差込レコードごとにWordドキュメントが生成されると便利(というか後々扱いやすい)なので、

akashi-keirin.hatenablog.com

こんな感じでWordドキュメントを大量生産することが多い。

摩訶不思議な不具合

差し込むデータは、相手先の名前だったり、日付だったりするのだが、場合によっては、字幅を揃えたいことがある。

そんなときに、差し込みフィールドの部分に均等割付を施す。

しかし、たまに困ったことが起こる。

データが差し込まれた瞬間とか、出来上がったWordドキュメントを開き直したときに、均等割付がめちゃくちゃになってしまうのである。

これは、職場のPCでしか今のところ起こらないので、そのものずばりをお見せできないのだけれど、擬似的に再現すると、

f:id:akashi_keirin:20190420074427j:plain

こんなふうにキッチリ揃えたはずなのに、

f:id:akashi_keirin:20190420074430j:plain

ドキュメントを開き直したら、こんなふうにガタガタになる、というイメージ。

で、これまたお見せできないのだけれど、それぞれの均等割付がなされている部分をクリックしてやると、だいたい元に戻る。なのに、その状態で上書き保存しても、開き直すとまたガタガタ……。

職場のPCでしか起きないので、Word2010のバグか何かだと思っていたのだけれど、職場のPCが2016になってからも引き続き起こる。家の2013ではまるで再現できないのに。

これの何が困るって、

自動印刷ができない

こと。

せっかく書類の量産を自動化しても、印刷したり、PDF化したりする作業が全部手作業だというのでは、非効率もはなはだしい。

そういうわけで、作ったのが

akashi-keirin.hatenablog.com

このFunctionなのであった。

Functionの改良

Excelからでも使えるように改良してみた。

リスト1 標準モジュール
Public Function setCursor(ByVal targetDoc As Document, _
                          ByVal targetPage As Long, _
                          ByVal targetLine As Long, _
                          ByVal targetCharacter As Long, _
                 Optional ByVal isToClick As Boolean = True) As Boolean
  setCursor = False
On Error GoTo Finalizer
  Dim wordApp As Word.Application
  Set wordApp = targetDoc.Parent
  Call wordApp.Selection.GoTo(What:=wdGoToPage, _
                              Which:=wdGoToAbsolute, _
                              Count:=targetPage)
  If targetLine = 1 Then
    'targetLineが「1」のときは移動しない。'
  Else
    Call wordApp.Selection.GoTo(What:=wdGoToLine, _
                              Which:=wdGoToRelative, _
                              Count:=targetLine - 1)
  End If
  Call wordApp.Selection.MoveRight(Unit:=wdCharacter, _
                              Count:=targetCharacter, _
                              Extend:=wdMove)
  If isToClick Then Selection.Select  '……(*)'
  setCursor = True
Finalizer:
  Set wordApp = Nothing
End Function

Selectionオブジェクトは、Word.Applicationの配下にあるので、Excelなど他アプリから操作するときは、Word.Applicationオブジェクトから指定しないと使えない。

Officeデベロッパー センターの記述によると、

ドキュメント ウィンドウ枠ごとに Selection オブジェクトは 1 つだけであり、アプリケーション全体で 1 つの Selection オブジェクトのみをアクティブにできます。 https://docs.microsoft.com/ja-jp/office/vba/api/word.selection

とのことなので、Word.Applicationオブジェクトは、対象のDocumentオブジェクトのParentプロパティから取得するのが良いと思った。

ちなみに、(*)の

If isToClick Then Selection.Select

は、カーソル位置を移動した後、その部分をクリックする動作を再現したつもり。

これでいいのかどうか、こんなのが必要なのかどうか、は不明。

使ってみる

次のコードで実験。

スト2 標準モジュール
Public Sub test02()
  Dim wordApp As New Word.Application
  wordApp.Visible = True
  Dim targetDoc As Word.Document
  Set targetDoc = wordApp.Documents.Open(ThisWorkbook.Path & "\ち~んw.docx")
  Dim i As Long
  For i = 1 To 5
    Call setCursor(targetDoc, 1, i, 2, True)
    Call WindowsAPI.waitFor(500)
  Next
  Call targetDoc.Close(SaveChanges:=False)
  Call wordApp.Quit
  Set wordApp = Nothing
End Sub

Excelから、同じフォルダ内にある「ち~んw.docx」というドキュメントを開いて、そのドキュメントの1ページ目にある1行目~5行目までの文字列の2文字目のところをそれぞれクリック(っていうか選択)する、というもの。

一瞬で終わってしまうと何をやっているのかわからないので、1行ごとに0.5秒ウェイトするようにしている。

WindowsAPIクラスについては、

akashi-keirin.hatenablog.com

コチラをどうぞ。

f:id:akashi_keirin:20190420074434g:plain

ちょいわかりにくいけど、こんな動作。

おわりに

こちらの情報によると、均等割付を字数単位で指定しているのが原因なのかも知れない。

一度、職場のPCでmm単位で指定して実験してみようと思う。