【実務・中級編】【初心者向け】セル内のテキスト量に応じて、行の高さを自動調整するマクロ – Word VBA解析バイブル

スポンサーリンク
スポンサーリンク

レイアウト崩れを根絶せよ:Word VBAにおける「動的テーブル制御」の設計思想

業務自動化の現場において、もっとも「現場の信頼」を失墜させるミスは何だと思うか?
それは、計算が間違っていることでも、処理が遅いことでもない。

「出力された帳票のレイアウトが、データ量によってグチャグチャになること」だ。

Excelであれば、セルはデータの器として機能し、表示範囲を広げれば済む話だ。しかし、Wordは「文書」である。文書には「美しさ」と「整合性」が求められる。セル内に溢れ出したテキストが隣の行を侵食したり、表がページを突き抜けたりするマクロは、プロフェッショナルの仕事とは呼べない。

今回は、初心者から脱却し、実務で通用する「堅牢な表生成ロジック」を構築するための、AutoFit(自動調整)の極意を伝授する。

1. なぜ、あなたのマクロはレイアウトを破壊するのか?

多くの初心者が陥るアンチパターンがある。それは、「テキストを流し込んだ後に、場当たり的にAutoFitを呼び出す」という手法だ。

' --- アンチパターン:素人の書き方 ---
For i = 1 To rowCount
    targetTable.Cell(i, 1).Range.Text = dataArray(i)
    targetTable.Rows(i).AutoFit ' ← 毎回これを呼ぶのは非効率かつ危険
Next i

なぜこれがダメなのか。理由は3つある。

1. 計算コストの増大: `AutoFit` はWordのレイアウトエンジンを再計算させる重い処理だ。ループ内で毎回呼び出すのは、エンジンに「一歩歩くたびに地図を書き直せ」と命令するようなもので、パフォーマンスを著しく低下させる。
2. 固定値との衝突: 行の高さ(`Height`)に数値が設定されている場合、AutoFitは無力化される。
3. 意図しない幅の変化: `AutoFit` の設定次第では、テキスト量に応じて「列の幅」まで勝手に変わってしまう。ユーザーが求めているのは「行の高さの調整」であって、「列幅の変動」ではないことが多い。

2. 堅牢な設計:プロフェッショナルが守る「3つの鉄則」

プロのアーキテクトは、データを流し込む「前」と「後」で、オブジェクトの状態を厳格に管理する。

鉄則①:RowHeightRule を「Auto」に固定せよ

Wordの行の高さには「ルール」がある。`wdRowHeightExactly`(固定値)が設定されていると、どれだけテキストが増えても行は広がりません。動的な調整を前提とするなら、必ず `wdRowHeightAuto` を指定しておく必要がある。

鉄則②:AutoFitBehavior を戦略的に使い分けよ

  • `wdAutoFitContent`: セル内のコンテンツに合わせて、列の幅を調整する。
  • `wdAutoFitWindow`: 表全体の幅を、ページ(ウィンドウ)の幅に合わせる。

実務では、多くの場合「列幅は固定し、行の高さだけを自動調整したい」という要求が来る。この場合、まず `wdAutoFitWindow` で表の骨格を決め、その後、行の高さルールを制御するのが正解だ。

鉄則③:オブジェクトのライフサイクルを意識せよ

大量のデータを流し込む際は、まず「器(テーブル)」の構造を完成させ、プロパティ(幅やルール)を確定させてから、最後にデータを流し込む。あるいは、流し込み完了後に「一括で」レイアウトを整える。

3. 【プロダクションコード】動的テーブル生成の決定版

以下に、実務でそのまま使える、保守性の高い設計パターンを示す。このコードは、単に動くだけでなく、後からの仕様変更(例:特定の列だけ幅を変えたい等)にも耐えうる構造にしている。

Option Explicit

''' <summary>
''' 実務レベルの表生成メインルーチン
''' </summary>
Public Sub GenerateRobustReport()
    Dim doc As Document
    Set doc = ActiveDocument
    
    ' 1. サンプルデータの準備 (本来はDBやExcelから取得)
    Dim data As Variant
    data = Array( _
        Array("ID", "項目名", "詳細説明"), _
        Array("001", "短文", "これは短いテキストです。"), _
        Array("002", "長文", "ここには非常に長いテキストが入ります。改行が含まれる場合や、" & _
                 "一文が極端に長い場合でも、行の高さが自動的に拡張され、" & _
                 "テキストがセルからはみ出さないように設計されています。"), _
        Array("003", "境界テスト", "連続する改行" & vbCrLf & vbCrLf & "による高さの変化を確認。") _
    )

    ' 2. テーブルの生成
    Dim rowCount As Long, colCount As Long
    rowCount = UBound(data) + 1
    colCount = UBound(data(0)) + 1
    
    Dim tbl As Table
    Set tbl = doc.Tables.Add(Range:=doc.Range(doc.Content.End - 1), _
                             NumRows:=rowCount, _
                             NumColumns:=colCount)
    
    ' 3. テーブルの基本プロパティ設定(構築フェーズ)
    With tbl
        .AllowAutoFit = True ' AutoFit機能を有効化
        .AutoFitBehavior wdAutoFitWindow ' まずはページ幅に合わせる
        .Borders.Enable = True ' 罫線を表示
        
        ' ヘッダー行のスタイル設定(実務ではここを分離する)
        Dim i As Long
        For i = 1 To colCount
            .Cell(1, i).Range.Text = data(0)(i - 1)
            .Cell(1, i).Range.Font.Bold = True
            .Cell(1, i).Shading.BackgroundPatternColor = wdColorGray10
        Next i
        
        ' 4. データの流し込み(注入フェーズ)
        Dim r As Long, c As Long
        For r = 2 To rowCount
            For c = 1 To colCount
                .Cell(r, c).Range.Text = data(r)(c - 1)
            Next c
        Next r
        
        ' 5. レイアウトの最終確定(最適化フェーズ)
        ' ここで「行の高さ」を自動調整ルールに強制設定する
        ApplyDynamicRowHeight tbl
    End With
    
    MsgBox "レポートの生成が完了しました。", vbInformation
End Sub

''' <summary>
''' テーブルの行高さをコンテンツに応じて自動調整する専用メソッド
''' </summary>
''' <param name="targetTable">対象となるTableオブジェクト</param>
Private Sub ApplyDynamicRowHeight(ByRef targetTable As Table)
    Dim rowIdx As Long
    
    On Error GoTo ErrorHandler
    
    ' 行ごとに高さルールを「自動」に設定することで、
    ' セル内のテキスト量に応じてWordが計算を行うように仕向ける
    For rowIdx = 1 To targetTable.Rows.Count
        With targetTable.Rows(rowIdx)
            .HeightRule = wdRowHeightAuto ' これが最重要:固定値(Exactly)を解除する
            .Height = 0 ' 高さを0に設定することで、最小値からの自動計算を促す
        End With
    Next rowIdx
    
    Exit Sub

ErrorHandler:
    Debug.Print "Error in ApplyDynamicRowHeight: " & Err.Description
    ' 実務ではここでログ出力やユーザーへの通知を行う
End Sub

4. アーキテクトからのアドバイス:運用のための注意点

このコードを実戦投入するにあたり、以下の2点を肝に銘じておけ。

データベース・外部連携時の「型」の罠

ExcelやSQL Serverからデータを取得する場合、`Null` 値や `Empty` 値が混入することがある。Wordの `Cell.Range.Text` に `Null` を直接渡そうとすると、実行時エラーで即死する。必ず `CStr()` 関数などで文字列型へ明示的にキャストするか、空文字 `””` への置換ロジックを挟め。

パフォーマンスの限界を知る

もし、生成するテーブルが数百行、数千行に及ぶ場合、`Table.Rows` コレクションへのアクセス自体がボトルネックになる。その場合は、テーブル全体に対して一度だけ `AutoFit` を適用し、個別の行操作を最小限にする設計へシフトせよ。

結論

「動くコード」を書くのは誰にでもできる。しかし、「壊れないコード」を書くには、オブジェクトがどのように描画され、どのようなルールに従って制御されているかという、内部メカニズムへの深い理解が必要だ。

`HeightRule = wdRowHeightAuto`。
この一行に込められた意味を、忘れるな。

タイトルとURLをコピーしました