【極限の知見】継ぎ接ぎ資料を「プロの成果物」へ昇華させる。スライドマスターのフォント強制統一術
こんにちは。現場の自動化を司るアーキテクトです。
「マクロの記録」でコードを書き始めた時期を、君は覚えているだろうか? 記録されたコードを見て、「なぜここで `Select` が必要なんだ?」「もっとスマートな書き方があるはずだ」と違和感を覚えたなら、君はすでに初級者の殻を破り、中級者への階段を登り始めている。
今日、君に伝授するのは、単なる「フォント変更マクロ」ではない。
あちこちからスライドをコピー&ペーストして作り上げられた、いわば「フランケンシュタイン状態」のプレゼンテーションを、社内標準の美しいデザインへと強制的に再構築(リビルド)する、プロフェッショナルな手法だ。
なぜ、スライド上の文字を全選択してフォントを変えるだけでは不十分なのか? その「本質的な理由」と、オブジェクトの階層構造を支配するコードを、共に見ていこう。
1. なぜ「全選択→フォント変更」では足りないのか?
多くのユーザーが陥る罠がある。それは、「スライド上の文字を変えれば、資料は綺麗になる」という思い込みだ。
PowerPointの構造は、単なる紙の束ではない。高度なオブジェクト・階層構造を持っている。
1. Slide Master(スライドマスター): 資料全体の「設計図」。ここに定義されたフォントが、全ての基本となる。
2. Layout(レイアウト): マスターから派生した、特定の配置パターン。
3. Slide(スライド): 実際にコンテンツが乗るページ。
4. Shape(シェイプ): テキストボックスや図形。
継ぎ接ぎの資料には、目に見えない「マスターの残骸」が潜んでいる。スライド上の文字を変えても、マスターに古いフォント定義が残っている限り、新しいスライドを追加したり、図形を複製したりした瞬間に、再び「異種フォント」が侵入してくるんだ。
真の自動化エンジニアは、「個々のスライド」ではなく「設計図(マスター)」を制圧する。これが、クリーンな資料を作るための鉄則だ。
2. 実践:フォント強制統一スクリプト
では、実際に魂を込めたコードを見てみよう。このコードは、スライドマスター、レイアウト、そして各スライドの全シェイプを走査し、指定したフォントへ強制的に書き換える。
ここで重要なのは、「英字フォント」と「日本語フォント(NameFarEast)」の両方を指定することだ。ここを怠ると、日本語だけが古いフォントのまま残るという、プロとして恥ずべき結果を招くことになる。
Option Explicit
''' <summary>
''' プレゼンテーション内の全フォントを社内標準に強制統一し、クリーンに保存する
''' </summary>
Sub UnifyPresentationFonts()
' --- 設定領域:ここを社内標準に合わせて書き換える ---
Const TARGET_FONT_NAME As String = "Arial" ' 英字フォント
Const TARGET_FONT_EAST As String = "游ゴシック" ' 日本語フォント
Const SAVE_PATH_SUFFIX As String = "_Cleaned" ' 保存ファイル名に付与する接尾辞
' --------------------------------------------------
Dim pres As Presentation
Dim sldMaster As Design
Dim sldLayout As CustomLayout
Dim sld As Slide
Dim shp As Shape
Dim targetPath As String
Set pres = ActivePresentation
' 画面更新を停止してパフォーマンスを向上させる(Excelとは異なり、PPTでは
' 完全な停止は難しいが、処理の高速化に寄与する考え方だ)
On Error GoTo ErrorHandler
Debug.Print "--- フォント統一処理を開始します ---"
' 1. スライドマスター(設計図)のフォントを制圧する
' これを行わないと、新しいスライドを作った時に古いフォントが復活する
For Each sldMaster In pres.Designs
' マスター自体のフォント設定
ApplyFontToShape sldMaster.SlideMaster, TARGET_FONT_NAME, TARGET_FONT_EAST
' 2. マスターに紐づく各レイアウトのフォントを制圧する
For Each sldLayout In sldMaster.SlideMaster.CustomLayouts
ApplyFontToShape sldLayout, TARGET_FONT_NAME, TARGET_FONT_EAST
Next sldLayout
Next sldMaster
' 3. 各スライド内の個別シェイプを走査する
' マスターを上書きしても、個別に設定された「上書きフォント」は残るため、ここが必要だ
For Each sld In pres.Slides
For Each shp In sld.Shapes
ApplyFontToShape shp, TARGET_FONT_NAME, TARGET_FONT_EAST
Next shp
Next sld
' 4. クリーンな状態での保存処理
' 元のファイルを破壊しないよう、別名で保存するのがプロの作法だ
targetPath = pres.Path & "\" & Left(pres.Name, InStrRev(pres.Name, ".") - 1) & SAVE_PATH_SUFFIX & ".pptx"
pres.SaveCopyAs targetPath
MsgBox "完了しました!" & vbCrLf & "保存先: " & targetPath, vbInformation, "成功"
Exit Sub
ErrorHandler:
MsgBox "エラーが発生しました。原因: " & Err.Description, vbCritical, "エラー"
End Sub
''' <summary>
''' 指定されたシェイプ内のテキストフォントを強制的に書き換える内部関数
''' </summary>
Private Sub ApplyFontToShape(ByRef targetObj As Object, ByVal fontName As String, ByVal fontEast As String)
Dim shp As Shape
' targetObjがSlideMasterやCustomLayoutの場合、その中のShapesをループする
' 単一のShapeが渡された場合にも対応できるように設計している
On Error Resume Next ' テキストを持たないシェイプでのエラーを回避
If TypeName(targetObj) = "Slide" Or TypeName(targetObj) = "CustomLayout" Or TypeName(targetObj) = "SlideMaster" Then
' マスターやレイアウトの場合
For Each shp In targetObj.Shapes
Call ProcessTextFrame(shp, fontName, fontEast)
Next shp
Else
' 単一のシェイプの場合
Call ProcessTextFrame(targetObj, fontName, fontEast)
End If
On Error GoTo 0
End Sub
''' <summary>
''' テキストフレームが存在する場合に、フォントを適用する
''' </summary>
Private Sub ProcessTextFrame(ByRef shp As Shape, ByVal fontName As String, ByVal fontEast As String)
' テキストを持っているか、グループ化されているかを確認
If shp.HasTextFrame Then
If shp.TextFrame.HasText Then
With shp.TextFrame.TextRange.Font
.Name = fontName ' 英字フォントの設定
.NameFarEast = fontEast ' 日本語フォントの設定(ここが極めて重要!)
End With
End If
' グループ化された図形の中にあるテキストも対象にする
ElseIf shp.Type = msoGroup Then
Dim i As Integer
For i = 1 To shp.GroupItems.Count
Call ProcessTextFrame(shp.GroupItems(i), fontName, fontEast)
Next i
End If
End Sub
3. アーキテクトの視点:コードの深淵を読み解く
このコードには、君が「記録マクロ」から卒業するために必要な、3つの重要な概念が組み込まれている。
① 再帰的な構造への対応(Recursion-like Logic)
見てくれた通り、`ProcessTextFrame` は、もしシェイプが「グループ化」されていた場合、その中のアイテムに対しても自分自身を呼び出している。
資料作成現場では、図形がグループ化されていることは日常茶飯事だ。単なるループでは、グループの奥底に隠れたテキストを見逃してしまう。「構造の深さ」を意識すること、これがプロの設計だ。
② `NameFarEast` という名の聖域
ここが最大のポイントだ。
VBAにおいて、`.Name` は主にラテン文字(英数字)を制御する。一方で、日本語のような東アジア言語を制御するのは `.NameFarEast` プロパティだ。
多くの初学者が「フォントが変わらない!」と嘆く原因は、このプロパティを無視しているからだ。「対象となるオブジェクトの全属性を把握する」。これが、バグを未然に防ぐ唯一の道だ。
③ `SaveCopyAs` による安全性
`Save`(上書き保存)ではなく `SaveCopyAs`(コピーを保存)を使っている点に注目してほしい。
自動化スクリプトを実行した際、予期せぬエラーでファイルが壊れたり、意図しない上書きが発生したりするのは、エンジニアとして最も避けたい事態だ。「入力(元ファイル)と出力(保存ファイル)を分離する」。これは、あらゆる自動化における黄金律である。
4. 陥りやすいエラーと対策
君がこのコードを運用する中で、遭遇するかもしれない壁についても触れておこう。
- 「読み取り専用」エラー:
ファイルが他のユーザーによって開かれている場合、保存に失敗する。実行前に、対象ファイルが他のプロセスに掴まれていないか確認するルーチンを入れるのが理想的だ。
- パフォーマンスの低下:
数千枚のスライドがある巨大なファイルでは、処理に時間がかかる。その場合は、スライドごとに処理を区切り、一定時間ごとに `DoEvents` を挟んでOSに制御を戻す工夫が必要になるだろう。
最後に:君へのエール
ここまで読み進めた君は、もう単なる「マクロ利用者」ではない。
オブジェクトの階層を理解し、属性の細部にまで目を配る、「エンジニアの思考」を手に入れつつある。
プログラミングとは、単に命令を並べることではない。対象となる世界の「構造」を理解し、その構造に対して最も美しく、最も安全な介入方法を選択する芸術だ。
このスクリプトをベースに、君なりのカスタマイズを加えてみてほしい。PDFへの一括変換機能や、特定のフォントサイズへの統一など、拡張の余地は無限にある。
さあ、次はどんな「不条理な資料」を、君のコードで美しく変えてみせるだろうか? 楽しみにしているよ。
