わーぷろおじさん

WordやOffice関連の小細工の備忘録。

【Excel VBA】簡単にNeポート番号付きのプリンタ名一覧を取得する裏技

コード

参照設定:Microsoft Shell Controls And Automation

Sub Test()
    Dim myPrinter As String
    myPrinter = Application.ActivePrinter
   
    Dim Shell As Shell32.Shell
    Set Shell = New Shell32.Shell
    Dim Printer As Shell32.FolderItem2
    For Each Printer In Shell.Namespace(ssfPRINTERS).Items
        On Error Resume Next
        Call ThisWorkbook.PrintOut(From:=0, ActivePrinter:=Printer.Name)
        On Error GoTo 0
        Debug.Print Application.ActivePrinter
    Next
   
    Application.ActivePrinter = myPrinter
End Sub

PrintOutメソッドのFrom:=0がポイント。To:=0でもCopiese:=0でもOK。エラーで印刷は実行されません。

※ポート番号なしのプリンター名の取得方法はShellの他にもいろいろですが説明は省略。

感想

エラーでPrintOutメソッドを寸止めしてるのが裏技っぽいので記事にしました。一覧の使い道(必要性)は分かりません。

【word vba】差し込み印刷をマクロで制御(備忘録)

基本操作

Sub testMMDS()
    Dim mmds As MailMergeDataSource
    Set mmds = ActiveDocument.MailMerge.DataSource
    
    Debug.Print mmds.ConnectString
    Debug.Print mmds.QueryString
    Debug.Print mmds.TableName
    Debug.Print mmds.Name
    
    Dim i As Long
    For i = 1 To mmds.RecordCount
        mmds.ActiveRecord = i
        Debug.Print mmds.ActiveRecord
        
        Dim mmdf As MailMergeDataField
        For Each mmdf In mmds.DataFields
            Debug.Print mmdf.Name & ":" & mmdf.Value
        Next
    Next
    mmds.ActiveRecord = wdFirstRecord
    ActiveDocument.MailMerge.ViewMailMergeFieldCodes = True
End Sub

※TableNameとNameは読み取り専用。

フィルター操作

テーブル名はエクセルワークシートを想定

参照設定:Microsoft VBScript Regular Expressions

Public Sub filterMMDS()
    On Error GoTo ErrorHandler
    Dim mmds As Word.MailMergeDataSource
    Set mmds = ActiveDocument.MailMerge.DataSource
    
    Dim re As RegExp
    Set re = New RegExp
    re.Pattern = "SELECT \* FROM `[^$]*\$[^`]*`"
    
    Dim mc As MatchCollection
    Set mc = re.Execute(mmds.QueryString)
    
    Dim BaseQuery As String
    BaseQuery = mc(0)
    
    Dim tmp As Variant
    tmp = Split(InputBox("nameとageをカンマ区切りで入力"), ",")
    
    Dim myName As String
    Dim myAge As Long
    myName = "'" & tmp(0) & "'"
    myAge = tmp(1)
    
    mmds.QueryString = BaseQuery & " WHERE name=" & myName & " AND age=" & myAge
    MsgBox "抽出件数は" & mmds.RecordCount & "件です。"
    Exit Sub

ErrorHandler:
    mmds.QueryString = BaseQuery
    MsgBox "抽出条件をクリアしました"
End Sub

※数値データをシングルクォテーションで囲ってもVBA上は動作するが、QueryStringにシングルクォテーションを残したまま保存すると、次回起動時にデータ参照エラーが出てしまうので、文字列データだけをシングルクォテーションで囲う。

※QueryStringのフィールド名はwordの仕様上バッククォートで囲うようだが、囲わなくてもOK。ファイル再起動時も影響なし(バージョンによるかも)

※使用できるSQL構文は、AND/OR、=/<>/</>/<=/>=、WHERE、ORDER BY、ASC/DESC

イベントハンドラ

差し込み印刷でファイルに出力したときに、出力先のdocumentオブジェクトを捕捉する例。

Documentモジュールに記載

Option Explicit
Private WithEvents WordApp As Word.Application
 
Private Sub Document_Open()
    Set WordApp = Word.Application
End Sub
 
Public Sub testMailMerge()
    Dim mm As MailMerge
    Set mm = ActiveDocument.MailMerge
    mm.Destination = wdSendToNewDocument
    mm.Execute 'イベント発生
End Sub
 
Private Sub WordApp_MailMergeAfterMerge(ByVal Doc As Document, ByVal DocResult As Document)
    Debug.Print DocResult.Name
End Sub

※クラスモジュールでの実装も可

※Document_Open以外でも任意のタイミングでWord.Applicationを捕捉すればよい

※testMailMergeで差し込み印刷を実行しているが、マクロからの実行でもリボンからの操作での実行でもイベントは捉えられる。

レコードごとに個別ファイル(docx, pdf)で保存

DocumentモジュールかClassモジュールに記載

Option Explicit
Private WithEvents WordApp As Word.Application
 
Public Sub SaveEachRecord()
    Set WordApp = Word.Application
 
    Dim mm As MailMerge
    Set mm = ActiveDocument.MailMerge
    mm.Destination = wdSendToNewDocument
 
    Dim mmds As MailMergeDataSource
    Set mmds = mm.DataSource
 
    Dim i As Long
    For i = 1 To mmds.RecordCount
        With mmds
            .ActiveRecord = i
            .FirstRecord = i
            .LastRecord = i
        End With
        mm.Execute 'イベント発生
    Next
 
    With mmds
        .ActiveRecord = wdDefaultFirstRecord
        .FirstRecord = wdDefaultFirstRecord
        .LastRecord = wdDefaultLastRecord
    End With
End Sub
 
Private Sub WordApp_MailMergeAfterMerge(ByVal Doc As Document, ByVal DocResult As Document)
    Dim mmds As MailMergeDataSource
    Set mmds = Doc.MailMerge.DataSource
 
    Dim OutputFile As String
    OutputFile = Doc.Path & "\" & Format(mmds.ActiveRecord, "00_") & mmds.DataFields("hogehoge").Value
 
    With DocResult
        .SaveAs2 FileName:=OutputFile & ".docx"
        .ExportAsFixedFormat OutputFileName:=OutputFile & ".pdf", ExportFormat:=wdExportFormatPDF
        .Close SaveChanges:=False
    End With
End Sub

【word】ルビを文字スタイルで管理(その2)

ルビを文字スタイルで管理

概要

前の記事で、wordのルビ機能によらないルビの実現及びスタイルでの管理方法を説明したが、今回はwordのルビ機能を使いながらルビのスタイル管理の方法について提唱する。

今回は書式の置換を用いて、一括でルビにスタイルを適用する。

手順

通常通り、wordのルビ機能を使いながら文章を作成し、後から(途中でもいいが)まとめてルビにスタイルを適用する。

(1)文字スタイルを作成

・スタイル名は「ルビ文字」など

・フォント:任意のフォント(段落フォント同じとする場合は指定しない)

・フォントサイズ:指定しない(既定のままでOK)

・位置:指定しない(既定のままでOK)

(2)書式の置換

フィールドコードが見える状態で下記の置換を行う

検索する文字列

hps[0-9]{1,2} \\o*\(\\s\\up [0-9]{1,2}\([!\)]{1,}

置換後の文字列

^&

オプション

ワイルドカード:有効

書式>スタイル>(1)で作成したスタイル(※置換後の文字列に適用させること)

(3)word再起動

上記置換では、ルビ文字以外にも文字スタイルが適用されるが、wordを再起動すると、ルビのフィールドコードのゾンビ仕様で、ルビ文字列以外に適用された文字スタイルが消えている。ゾンビと共存の道ができた。

前回との比較

前回はフォント、フォントサイズ、位置の全てをスタイルに任せることとしたが、ルビの入力が手間という致命的な欠陥を持っていた。

今回の方法は、普通にルビ機能を使って、気が向いた時に書式の置換を行えば一括で行えるので利便性は増した。ルビ機能に従っているので均等割り付け2も利用可能である。

利用上のポイント

ルビの文字スタイルには個別のフォントを設定しなければ、段落フォントが適用されるので、テーマのフォントの変更や、段落スタイルのフォント変更などに自動で追従できる。

ルビのフォントサイズと位置は、文字列置換による対応が必要だが、下記の置換でスタイルも含めて一括で置換できる。

 

検索する文字列

hps[0-9]{1,2}( \\o*\(\\s\\up) [0-9]{1,2}(\([!\)]{1,})

置換後の文字列(例)

hps12\1 10\2

(※例の12と10の箇所が置換後のサイズと位置なので、任意で設定する)

オプション

ワイルドカード:有効

置換後の文字列へのスタイル設定

関連記事

word-ozisan.hatenablog.com

word-ozisan.hatenablog.com

【word】縦中横を文字スタイルで管理(縦書き文書・横書き文書切替対応)

縦中横を文字スタイルで管理

概要

縦書きと横書きを相互に切り替えられるよう、縦中横を文字スタイルで管理する。

なお、縦中横などの拡張書式(英語名:Asian Layout)は、スタイルの設定ダイアログからは設定できない。

よって、スタイルの修正ではなく、スタイルセットの切替により縦中横の切替を実現する。

手順

(1)縦中横の文字列を作成

  • 文書中に標準スタイルの段落に適当に作成する。縦中横以外の余計な書式設定は行わない。
  • 縦中横オプションの「行の幅に合わせる」の設定は任意。場所によって使い分けたい場合は、両方作成する。
  • 横書き文書のままでも可。

(2)文字スタイルに登録

裏技的方法だが、文字スタイルに拡張書式を設定する方法

  • 縦中横を設定した文字列を選択した状態で「新しいスタイル」を作成する。
  • 名前:任意(単純に「縦中横」で可。複数の縦中横スタイルを作りたい場合は、識別できる名前)
  • 種類:文字

(3)スタイルセットとして保存

  • デザインタブから「新しいスタイルセットとして保存」を指定
  • 名前:任意(例:縦中横オン)

(4)縦中横スタイルの変更(縦中横解除)

  • 標準スタイルの段落中の文字列(標準スタイル以外の書式がついていない箇所)を選択する。
  • 縦中横を設定した文字スタイルのオプションを開き、「選択個所と一致するように●●●を更新する」を実行する。(※●●●は設定したスタイル名)

(5)スタイルセットとして保存

  • 名前:任意(例:縦中横オフ)

使い方

  • デザインタブからスタイルセットを切り替える。
  • 文書の「文字列の方向」から縦書き・横書きを切り替える。

留意事項

  • 縦中横を切り替えることによって、当該箇所の字送り幅、行送り幅が変化するため、行の折り返し箇所、改ページ箇所がずれる場合があることに留意。
  • スタイルを変更する場合は、全体のスタイルが完成した後に、片割れのスタイルをセットを作成すること。途中でスタイルを変更する場合は、片割れのスタイルセットを上書き更新すること。
  • 縦中横を解除したスタイルセットで、文字列に縦中横スタイルを当てても、変化は見られないが、スタイルセットを切り替えればきちんと縦中横になる。

個人的意見

パソコンは縦書きよりも横書きの方が適していると思われるので、最終的に縦書きとする文書でも横書きで作成したほうが効率がよい場合もある(特に文字中心の文書)。体裁を整える作業は最後にまとめて行えばよい。

  • マウスのスクロールは垂直の方が早い(まあ元々wordには縦書き文書の横スクロールはありませんが)
  • IMEの変換候補の表示方法は横書きの方がよい。MS IMEではTabキーで変換候補を沢山表示させることができる。

その他検討した内容

  • VBAでスタイルを設定できないか検討したが、無理っぽい(拡張書式はFontのメンバーではなく、Rangeのメンバーなので、Styleから設定不可)。
  • XML(OOXML)を編集できれば可能なのだが、開いているファイルのXML(OOXML)が編集できるものなのか分からず断念。ファイルを閉じていたとしても、ZIPファイルの中身を編集できるものか分からず断念。仮に出来る方法があるとしても、標準環境では出来ないと想定し断念。

関連記事

word-ozisan.hatenablog.com

 

【word】ルビを文字スタイルで管理

ルビを文字スタイルで管理

概要

通常、ルビの一括管理はフィールドコードの文字列置換によって行うことが多いと思われるが、当記事では新しい方法として文字スタイルによる管理を提唱する。

手順

(1)文字スタイルを作成

・スタイル名は「ルビ文字」など

・フォント:任意のフォント(段落フォント同じとする場合は指定しない)

・フォントサイズ:任意の値

・位置:「上げる」「任意の値(10ptくらい)」

※位置は書式>フォント>詳細設定の項目

(2)フィールドコードを作成

{EQ \o\ac(ユンピョウ,元彪)}

・上記例の\acオプションは中央揃え。必要に応じて設定(説明省略)

・ルビとルビを振られる文字列の順番は問わない。

(3)フィールドコード内のルビ文字列に文字スタイルを当てる。

思ったこと

一個一個フィールドコードを作成して、スタイルを当てるのは結構手間なので、マクロを用意する必要があると感じた。

表記とルビを一緒に入力するフォームがいいのか、選択した表記に対して、ルビを入力するフォームがいいのか。

まあ当ブログでは、作成例は示しませんが。

留意事項

この方法では、「均等割り付け2」の再現ができないと思われます。

その他

ルビのフィールドコードの凶暴さについては下記記事参照

word-ozisan.hatenablog.com

(追記)

word-ozisan.hatenablog.com

【word】ルビの挙動(ゾンビ仕様)

ルビのフィールドコード



ルビのフィールドコード

ルビボタンでルビを作成すると下記のようなフィールドコードが作成される。

{EQ \* jc2 \* "Font:游明朝" \* hps10 \o\ad(\s\up12(ユン・ピョウ),元彪)}

\oスイッチは重ね文字で、\sスイッチは文字列の上下位置をずらすもの。

単純に「重ねた文字列を上下にずらす」という仕組み。

\oスイッチと\sスイッチについては、フィールドコードを使えるものであれば大した問題ではない。

EQから\oスイッチの間の、三つの一般書式スイッチ(\*)が、かなり特殊。

 

第1一般書式スイッチ:配置

(jc0:中央揃え、jc1:均等割り付け1、jc2:均等割り付け2、jc3:左揃え、jc4:右揃え、jc5:右縦寄せ)

第2一般書式スイッチ:ルビのフォント指定

第3一般書式スイッチ:ルビのフォントサイズ

(簡便のため以下、第1スイッチ、第2スイッチ、第3スイッチということとする)

 

第2、第3スイッチは、\oスイッチ内の文字列に直接フォント設定を当てても無効化する。

第1スイッチは配置設定以外にも、\oスイッチのオプション無効化とフィールドコードの挙動を制御する特殊なスイッチである(後述)。

ルビの最小構成

さて、wordの機能(上述の3つの一般書式スイッチ)を使わなくとも、ルビを振ることはできる(一部できない機能はある)。

上述の\oスイッチと\sスイッチだけでフィールドコードを作成すればよい。

最小のルビは下記のとおり。(※オプションについての説明は省略)

{EQ \o\ad(\s\up12(ユン・ピョウ),元彪)}

この場合、ルビ部分のフォントおよびフォントサイズはフィールドコード内のルビ文字に当てられているフォントに従う。

よって、ここに文字スタイルを当てれば、フォントおよびフォントサイズを管理することができる。

ただし、一部できない機能として、wordのルビの割り付けの「均等割り付け2」があることに留意。

ゾンビな第1一般書式スイッチ

先に述べた通り第1スイッチはフィールドコードの挙動にまで影響力を及ぼす強力な仕様となっている。

(1)再生

フォントやフォントサイズを第2、第3スイッチから解放するため、第2、第3スイッチを削除しようとするかもしれないが、それは無駄である。第1スイッチを完全に消滅させなければ、第1スイッチは第2、第3スイッチを復活させてしまう。

(例)

第2、第3スイッチを削除

{EQ \* jc2 \o(\s\up12(ユン・ピョウ),元彪)}

(文書を保存して閉じで、再び開く)

{EQ \* jc2 \* "Font:游明朝" \* hps10 \o\ad(\s\up12(ユン・ピョウ),元彪)}

第2、第3スイッチが復活する。とどめを刺すためには、ゾンビ映画の如く、頭をぶち抜かなければならない。

(2)暴走

\oスイッチの中の順番(元彪とユン・ピョウ)を変えてみたら、とんでもない挙動をした。通常であれば、\oスイッチ内の順番は逆でも問題ない。\sスイッチが含まれていようとも。

(例)

{EQ \* jc2 \* "Font:游明朝" \* hps10 \o\ad(元彪,\s\up12(ユン・ピョウ)}
洪金寶,成龍。
{EQ 李小龍}

上記のフィールドコードを表示すると下記のようになる。

\oスイッチの第1引数「元彪」は無視され、\sスイッチ以降を第1引数と認識している。

さらに、第1引数はフィールドコード外に飛び出て、地の文のカンマを拾って第1引数の終わりとしている。

さらに、第2引数も地の文から始まって、次のフィールドコードの終わりを見つけて、第2引数の終わりとしている。

ゾンビ化した元彪は仲間たちを食い散らかしてしまったのだ。

 

続いて、このファイルを保存して、再度開くとフィールドコードは下記のように自動修正される。

{EQ \* jc2 \* "Font:游明朝" \* hps10 \o\ad(\s\up 12(ユン・ピョウ),\s\up12(ユン・ピョウ)}

フィールドコードを表示すると、

ゾンビ化した元彪は夜明けともに朽ち果ててしまったとさ…。

第2、第3一般書式スイッチのゾンビ仕様

第2スイッチ(フォント)

第2スイッチのフォント名を書き換えると文書上そのとおり反映されるが、ファイル再起動後、変更したはずの第2スイッチの内容は、\sスイッチ内のルビ文字に当てられているフォントに戻される。

ルビ文字のフォントを変更した場合、直ちには反映されないが、ファイル再起動後に第2スイッチの内容が、ルビ文字フォントの内容に自動修正され反映される。

(ネット上で、フォント名置換でフォントを変更できるような記事があったが、私の環境では上記の通り、フォント名置換では不十分な変更となる。環境によって異なるのだろうか?)

第3スイッチ(フォントサイズ)

ルビ文字のフォントを変更しても基本的には反映されず、第3スイッチがルビのフォントサイズを決定している。

第3スイッチを削除して、ファイル再起動すると、ルビ文字に当てられているフォントサイズで第3スイッチが復活する。

幻のjc5(右縦寄せ)

右縦寄せについては下記ブログを参考にさせていただきました。

stars-have-fallen.hatenablog.jp

{EQ \* jc5 \* "Font:游明朝" \* hps10 \o(\s\up12(ユン・ピョウ),元彪)}

縦書きと横書きで挙動が異なる…。通常のフィールドコードだけでは再現できない。けど、横書きで右縦寄せを必要とするシーンが思いつかない。

感想

ルビが単純なフィールドコードだけで構成されているわけではないことが理解できたが、かなり乱暴な仕様で唖然とした。マイクロソフトがルビを導入する際、通常のフィールドコードだけで実装できなくて、苦渋の決断で専用の仕様を導入したんだろうなと、勝手に想像してしまう。

ルビの体裁管理については、「均等割り付け2」を捨てれば、文字スタイルによる管理が可能であることも確認できた。これについては今後記事にしていきたい。

最後に、jcってなんなんですかね?justification?japanese-chinese?

 

(追記)

word-ozisan.hatenablog.com

word-ozisan.hatenablog.com

【word】字送り幅・フォントサイズ・文字間隔の関係

字送り幅・フォントサイズ・文字間隔の関係

基本的事項

文字の基本的な字送り幅を設定する項目は下記2点

  • ページ設定の字送り幅
  • フォント書式の文字間隔

ページ設定の字送り幅はデフォルト状態では、フォントサイズとなっている。横書き文書の文字の縦の並びを揃えたりする場合は、ページ設定で文字数・字送り幅を設定する。

説明

タイトル画像はページ設定の字送り幅12ptのフォーマットで、フォントサイズ、文字間隔を調整した例である。段落幅は480ptで12pt×40字のベタ組である。

  • ①はフォントサイズ=字送り幅。
  • ②~⑤より、フォント書式の文字間隔は2バイト文字には2倍効いていることが確認できる(「1pt広く」の設定で2pt広くなり、「1pt狭く」の設定で2pt狭くなる)
  • 文書中の一部のフォントサイズを変更した場合、ページ設定の字送り幅と標準フォントサイズの差が維持される。(標準フォントサイズ12pt、字送り幅14ptの文書の一部で8ptのフォントを使用したらその部分の字送り幅は10ptとなる)(フォントサイズごとに最小値はある)
    (②~⑤から、文書としては標準フォントサイズ=字送り幅なので、文書の一部のフォントサイズを変更しても、当該フォントサイズ=字送り幅が維持されることが確認できる)
  • 標準フォントのサイズを変更した場合、ページ設定の字送り幅はフォントサイズの差を維持する(上述の一部のフォントサイズ変更と挙動は同じ)。標準フォントのサイズを変更した場合は、通常、右余白が過剰になりやすいので、サイズを変更したら、ページ設定の字送り幅を確認・調整する必要がある。
  • 最終的な字送り幅は、文字列の字送り幅と、フォント書式の文字間隔を合計した値で決まる(文字間隔は2バイト文字には2倍効くことに留意)。下線、網掛け、マーカーはこの最終的な字送り幅に対して適用される。
  • ③より、ページ設定の字送り幅を、フォントサイズより大きくした場合、文字列は段落の右端に余白ができてしまうことが確認できる(極端な設定をしなければ気にならない)。
  • ページ設定の字送り最小値は、標準フォントサイズの90%
  • ページ設定の字送り最大値は、1584pt

留意

例では、異なるフォントサイズでも、文字間隔の調整によって字送り幅を維持する例を示したが、あくまで字送り幅・フォントサイズ・文字間隔の関係を示すための例であり、このような文字組を勧めるものではない。

関連記事

word-ozisan.hatenablog.com