適材適所

パソコン作業の自動化・効率化のための情報を発信するブログ(VBA,PowerShellなど)

ExcelVBAで差し込み印刷もどきをやってみる

Excel業務あるあるシリーズ

どこかの誰かが、どこかで苦戦しているかも知れない、自動化したいけど、なかなかいい考えが浮かばない・・・。

そんなよくありそうな作業の悩みを自動化しようという、このシリーズ。

今回は「差し込み印刷」もどきです。

Excelで差し込み印刷

Wordなら簡単にできる差し込み印刷ですが、Excelで同じことをやろうとすると、これが中々一筋縄ではいきません。

本当はExcelで作った帳票に差し込み印刷的なことをやりたいけど、しょうがないかいからWordでやっている・・・なんて人もいるかも知れませんね(聞いたことないけど)。

今回は、Excelで差し込み印刷もどきをやる、ちょっとしたアイディア(コード)を紹介しようと思います。

想定されるケース

・差し込みたい帳票はExcelで作成済み。わざわざWordで作り直すのも面倒・・・。
・Wordは動きがよくわからないから使いたくない!というWordはちょっと・・・の人。
・Wordで帳票作るの超面倒。って人

はい、全て私のことです。

では、次に具体的にどんな風にやるのか見てみましょう。

Excelの差し込み印刷の考え方

1.帳票のひな形を作っておく
2.帳票のひな形に項目名を埋め込む
3.埋め込んだ項目名を置換して印刷する
4.データが終わるまで繰り返す

こう書き出してみると、とっても単純ですね。

同様にプログラムも、そこまで手の込んだことは必要ありません。

Excelの構成もシンプルです。

ブックの構成

ひな形とデータの2つを用意します。

ひな形はなんでもいいのですが、こんなのありそう、ということで行政っぽい申請書を準備しました。

ポイントは<<ふりがな>>のような、二重のカッコで囲まれた部分です。

これが埋め込まれた項目名です。

f:id:shinmai_papa:20191119171723p:plain

転記するデータは、なんちゃって個人情報を使わせていただこうと思います。

なんちゃって個人情報

名前,ふりがな,アドレス,性別,年齢,誕生日,婚姻,都道府県,携帯,キャリア,カレーの食べ方
哀川 ジョージ,あいかわ じょーじ,aikawa_george@example.com,男,27,1992/2/29,未婚,長野県,080-7431-4514,au,奥ルー・せき止め派
野田 愛子,のだ あいこ,noda_aiko@example.com,女,76,1943/5/23,既婚,新潟県,080-7608-6149,ドコモ,奥ルー・別口派

この個人情報をひな形に埋め込まれた項目名と置換しつつ、差し込みを行おう、ということです。

コードの実装

Sub sashikomi_sample()
    Const TEMPLATE As String = "template"
    Const DATA     As String = "data"
    
    Application.ScreenUpdating = False
    
    Dim shTemplate As Worksheet: Set shTemplate = Worksheets(TEMPLATE)
    Dim shData As Worksheet: Set shData = Worksheets(DATA)
    Dim rngObj As Range
    
    '列番号を取得
    Dim collData As Collection: Set collData = New Collection
    Dim lastCol As Long: lastCol = shData.Cells(1, Columns.Count).End(xlToLeft).Column
    Dim i As Long
    For i = 1 To lastCol
        collData.Add Item:=i, Key:=shData.Cells(1, i).Value
    Next i
        
    'データを差し込む
    Dim lngTargetRow As Long
    Dim strKey As String
    Dim lngLastRow As Long: lngLastRow = shData.Cells(Rows.Count, 1).End(xlUp).Row
    
    For lngTargetRow = 2 To lngLastRow
        '差し込み先シートを削除する
        On Error Resume Next
        Application.DisplayAlerts = False
        Worksheets("差し込み先").Delete
        Application.DisplayAlerts = True
        On Error GoTo 0
    
        '新しい差し込み用シートを用意する
        Dim shNew As Worksheet
        shTemplate.Copy after:=Worksheets(DATA)
        Set shNew = ActiveSheet
        shNew.Name = "差し込み先"
        
        '差し込み先シートの値が入っているセル範囲を取得する
        Dim rngNewSh As Range: Set rngNewSh = shNew.UsedRange.SpecialCells(xlCellTypeConstants)
        
        For Each rngObj In rngNewSh
            '差し込み先かどうか判定
            If rngObj.Value Like "<<*>>" Then
                strKey = Replace(Replace(rngObj.Value, "<<", ""), ">>", "")
                rngObj.Value = shData.Cells(lngTargetRow, collData(strKey))
            End If
        Next rngObj
        '印刷プレビューを出す
        shNew.PrintPreview
    Next lngTargetRow
    
    Application.ScreenUpdating = True
    
End Sub

コードの解説

    Const TEMPLATE As String = "template"
    Const DATA     As String = "data"

シート名だけ定数を用意しています。なんだか中途半端ですが。

    Application.ScreenUpdating = False

画面の更新を停めます。定石ですね。

    Dim shTemplate As Worksheet: Set shTemplate = Worksheets(TEMPLATE)
    Dim shData As Worksheet: Set shData = Worksheets(DATA)
    Dim rngObj As Range

変数の割り当てや変数の準備をしています。

   '列番号を取得
   Dim collData As Collection: Set collData = New Collection
   Dim lastCol As Long: lastCol = shData.Cells(1, Columns.Count).End(xlToLeft).Column
   Dim i As Long
   For i = 1 To lastCol
       collData.Add Item:=i, Key:=shData.Cells(1, i).Value
   Next i

dataシートの列名とセルの列番号をマッピングしています。 詳しくはこの記事に書いております。

www.tekizai.net

     'データを差し込む
    Dim lngTargetRow As Long
    Dim strKey As String
    Dim lngLastRow As Long: lngLastRow = shData.Cells(Rows.Count, 1).End(xlUp).Row

データを差し込むための準備。各種変数を宣言、割り当てです。

    For lngTargetRow = 2 To lngLastRow

dataシートのレコード分、処理を行います。

        '差し込み先シートを削除する
        On Error Resume Next
        Application.DisplayAlerts = False
        Worksheets("差し込み先").Delete
        Application.DisplayAlerts = True
        On Error GoTo 0

既に「差し込み先」という名前のシート名があるとエラーになるので、削除しておきます。

       '新しい差し込み用シートを用意する
        Dim shNew As Worksheet
        shTemplate.Copy after:=Worksheets(DATA)
        Set shNew = ActiveSheet
        shNew.Name = "差し込み先"

templateシートをコピーし、差し込み先となるシートを新しく用意します。

         '差し込み先シートの値が入っているセル範囲を取得する
        Dim rngNewSh As Range: Set rngNewSh = shNew.UsedRange.SpecialCells(xlCellTypeConstants)

先ほど用意した、差し込み先のシートの中で、値が入っているセル範囲を取得しています。

「.SpecialCells(xlCellTypeConstants)」をつけることで、値が入っているセルだけを取得することができます。

      For Each rngObj In rngNewSh
            '差し込み先かどうか判定
            If rngObj.Value Like "<<*>>" Then
                strKey = Replace(Replace(rngObj.Value, "<<", ""), ">>", "")
                rngObj.Value = shData.Cells(lngTargetRow, collData(strKey))
            End If
        Next rngObj

先ほど取得したセル範囲に対して、1セルずつ走査し、値が「<<」と「>>」で囲まれている場合、差し込み項目と判断しています。

今回は<<○○>>としましたが、どんな記号でも大丈夫です。

                rngObj.Value = shData.Cells(lngTargetRow, collData(strKey))

ここで差し込み先シートの値を置換しています。

        '印刷プレビューを出す
        shNew.PrintPreview

差し込み先シートを印刷プレビューします。

実行してみる

今回、例のため、データは2件です。実行しみると・・・。 f:id:shinmai_papa:20191122170002p:plain

おお、印刷プレビューが出て・・・ f:id:shinmai_papa:20191122170027p:plain

ちゃんと、2件が印刷プレビューされました。

最後に

Excel VBAによる差し込み印刷もどきを作ってみました。

処理速度など、もっと改善できるコードはありますが、何かの参考になれば。

これで、苦しんでいる人が一人でも救われれば・・・。

ここまでお読みいただき、ありがとうございました。