Visio VBAを掌握する極限の知見:Shape.Charactersが引き起こす罠と、部分テキスト装飾の極意
業務自動化の現場において、Visioの図面生成を完全にプログラム化する要求は数多く存在する。フローチャートの自動生成、ネットワーク図の動的構築、あるいはインフラ構成図の自動更新などだ。
その際、避けて通れないのが「シェイプ内のテキスト操作」である。
「シェイプ全体の文字列を変更するだけなら `Shape.Text` に代入すればいい」——そう考えていた時期が、誰にもあるはずだ。しかし、実務の要求は常にその先を行く。
- 「ステータスを表すキーワード(例: `[CRITICAL]`)だけを赤字にし、フォントサイズを上げたい」
- 「複数行のテキストのうち、特定の数値部分だけを強調表示したい」
この要件を満たすために `Shape.Characters` プロパティを触った瞬間、多くの開発者がVisio固有の奇妙なオブジェクトモデルと、パフォーマンス劣化の沼にハマり込む。
今回は、Visio VBAの深部を知り尽くしたアーキテクトの視点から、`Characters` プロパティを完全に手懐け、バグなく高速に動作するプロダクションコードの書き方を伝授する。
—
なぜ `Shape.Text` ではダメなのか? オブジェクトモデルの本質
Visioの `Shape` オブジェクトにとって、テキストは単なる「文字列データ」ではない。それは形状(Geometry)やシェイプシート(Sheet)の数式群と同等の、独立したリッチテキストストリームとして存在している。
`Shape.Text = “サーバー: 正常”` と書いた場合、Visioは内部で既存の文字ストリームを全破棄し、デフォルトのフォントとスタイルで文字列を再構築する。つまり、文字列の一部だけの色やフォントサイズを変更するという概念が、単純なテキスト代入には存在しないのだ。
部分的な装飾を行う唯一の入り口が、`Shape.Characters` プロパティである。
`Characters` オブジェクトの残酷な真実
`Shape.Characters` は、文字列の「範囲(レンジ)」を指し示す。Excel VBAの `Range` オブジェクトに似ているが、Visioのそれは非常に重い。
1. 暗黙の再描画コスト: `Characters` オブジェクトのプロパティ(`CharProps` や `ParagraphProps`)を変更するたびに、Visioは画面の再描画とレイアウト計算を試みる。これをループ内で無計画に行うと、数個のシェイプ処理だけで数秒のフリーズを引き起こす。
2. インデックスのズレ問題: 文字列の長さを動的に変更したり、文字範囲を指定してスタイルを適用する際、文字位置(Begin / End)の計算を誤ると、意図しない文字が赤字に染まるか、最悪の場合は実行時エラー(COMException)でVBAがクラッシュする。
これらを克服し、実務に耐えうる堅牢なコードを書くための設計思想を次節で解説する。
—
堅牢な設計:バグを生まない「一括適用アプローチ」
実務でテキストの動的装飾を行う際、以下の原則を遵守しなければならない。
1. 画面描画の完全な抑制(`ScreenUpdating` の無効化はVisioでは通じない):
Excelのように `Application.ScreenUpdating = False` が万能に効くわけではない。Visioで最も効く高速化は、シェイプのイベント発火の抑制と、トランザクションの最小化である。
2. 文字列の検索と範囲特定をコード側で完結させる:
VisioのUIに依存せず、VBAの `InStr` や正規表現を用いて、ターゲット文字列の開始位置(`Begin`)と終了位置(`End`)を正確に算出し、一気に流し込む。
3. エラーハンドリングの徹底:
対象のキーワードが存在しない場合のフォールバック(例外処理)を必ず実装する。これがないと、データソース側のわずかな揺れでシステムが停止する。
—
【プロダクションコード】指定キーワードを赤字・太字にする汎用プロシージャ
以下に、実務の現場でそのまま組み込める、堅牢で洗練されたVBAモジュールを提供する。
このコードは、指定したシェイプ内の特定のキーワード(例: `[ERROR]` や `[NG]`)を検出し、その部分だけを赤字かつ太字に変えるものである。
Option Explicit
”’
”’
Public Sub FormatKeywordInShape(ByVal targetShape As Visio.Shape, ByVal keyword As String)
‘ 厳密な事前チェック
If targetShape Is Nothing Then Exit Sub
If Len(keyword) = 0 Then Exit Sub
‘ テキストを持たないシェイプ(グループやマスターなしの図形など)のガード
If targetShape.CellExists(visCharacterCount, False) = False Then Exit Sub
Dim fullText As String
fullText = targetShape.Text
‘ キーワードが含まれているか確認
Dim keywordPos As Long
keywordPos = InStr(1, fullText, keyword, vbBinaryCompare)
If keywordPos > 0 Then
On Error GoTo ErrorHandler
‘ Visioのトランザクション開始(パフォーマンス向上とロールバックのため)
Dim undoScopeID As Long
undoScopeID = Application.BeginUndoScope(“キーワードの動的装飾”)
‘ Charactersオブジェクトを取得
‘ 引数:Begin(1ベース), End(文字数ではなく位置。全選択なら 0, 0 だが今回は範囲指定)
‘ ※Visioの文字位置指定は 0 起点の文字オフセットである点に注意
Dim chars As Visio.Characters
Set chars = targetShape.Characters
‘ 該当キーワードの部分を指定
‘ Beginは「文字の開始位置(0始まり)」,Endは「終了位置」
chars.Begin = keywordPos – 1
chars.End = (keywordPos – 1) + Len(keyword)
‘ スタイルの適用(赤字、太字)
chars.CharProps(visCharacterColor) = RGB(255, 0, 0)
chars.CharProps(visCharacterBold) = True
‘ 変更を確定してUndoスコープを閉じる
Application.EndUndoScope undoScopeID, True
Exit Sub
ErrorHandler:
‘ エラー発生時はUndoして安全に抜ける
Application.EndUndoScope undoScopeID, False
MsgBox “テキスト装飾中にエラーが発生しました: ” & Err.Description, vbCritical, “VBA Error”
End If
End Sub
コードの解説とアーキテクトのこだわり
1. `visCharacterCount` の存在確認:
すべてのVisioシェイプがテキストを持てるわけではない。テキストを持たないシェイプに対して `Characters` を操作すると実行時エラーになるため、`CellExists` で事前に安全性を担保している。
2. Visio独自のインデックス仕様(0基点):
VBAの `InStr` は `1` 基点だが、Visioの `Characters.Begin` / `End` は `0` 基点の文字オフセット を要求する。そのため、`keywordPos – 1` という正確なインデックス変換を行っている。ここを間違えると、文字がずれるかクラッシュする。
3. Undoスコープ(`BeginUndoScope` / `EndUndoScope`)の活用:
実務ツールにおいて、予期せぬエラーで図面が破壊されることは絶対に防がなければならない。トランザクションを張ることで、万が一エラーが起きても処理を安全にロールバックできる設計にしている。
—
データベース・ファイル連携時の実務上の注意点
この自動化をCSV、Excel、あるいはSQL Serverなどの外部データソースと連携させる場合、以下の罠に注意してほしい。
- 改行コードの罠:
外部から取り込んだ文字列(特にCSVやWeb API経由)には、`vbCrLf`(CR+LF)が含まれていることが多い。Visioのシェイプ内では改行は `1文字` としてカウントされるが、環境によってコードが混在すると `InStr` の位置ずれを起こす。データ取り込み時に `Replace(text, vbCrLf, vbLf)` などで改行コードを正規化する前処理が必須である。
- フォント依存の問題:
プログラムから色や太字を強制的に変更しても、図面側で使用しているフォント(例: 游ゴシック、メイリオなど)がそのウェイト(太字)をサポートしていない場合、Visioが独自に偽似太字(シミュレーション)を生成し、印刷時やPDF変換時に文字が潰れる原因になる。動的装飾を行うシェイプのフォントは、必ず「MS ゴシック」や「Arial」など、ウェイトが確実に入っている標準フォントに固定すること。
—
エピローグ:真の自動化エンジニアを目指して
`Shape.Characters` を用いたテキスト装飾は、一見すると地味なテクニックに思えるかもしれない。しかし、オブジェクトモデルの挙動を完全に理解し、メモリ、インデックス、トランザクションの隅々にまで気を配ったコードを書くことこそが、「壊れない、文句を言われない業務ツール」を生み出す唯一の道である。
あなたの書くマクロが、現場の担当者の手作業を何時間も削減し、ミスを根絶する。その誇りを胸に、今日のコードをあなたの開発環境に組み込んでほしい。
