Visio VBAの深淵:Shape.Textの「破壊」を防ぎ、動的書式を掌握する
Visioの自動化において、`Shape.Text = “New Text”` と記述するその瞬間、あなたは図形がこれまで積み上げてきた「魂」——すなわち、丁寧に配置された部分書式をすべて消し去っている。
この残酷なリセットは、初学者が最初に直面する壁であり、中級者がメモリリークと共に放置する「負債」の源泉だ。今日は、Visioのオブジェクトモデルの深層に潜り、`Characters`オブジェクトを駆使して、既存の書式を保持したまま文字列を操作する「外科手術」の手法を伝授する。
—
1. なぜ Shape.Text は「破壊的」なのか
Visioの`Shape.Text`プロパティは、セッターを叩いた瞬間にそのShape内の`Character`コレクションを強制的にクリアし、新しいテキストで上書きする。これはVisioの内部構造(ShapeSheet)において、テキストセルの更新が全スタイル情報を再初期化するためだ。
大規模なドキュメント生成や、データソースと同期するダイアグラムにおいて、これを多用すればスタイル管理は破綻する。解決策はただ一つ。`Shape.Characters`オブジェクトを介し、バイナリレベルでオフセットを指定した操作を行うことだ。
—
2. 実装:部分書式を保持する「非破壊」更新術
以下のコードは、既存のテキストの末尾に、元のスタイルを維持しつつ新しい文字列を追加、あるいは特定範囲のスタイルをプログラムから制御する際のテンプレートだ。
‘ @description: 部分書式を破壊せずにテキストを変更する高精度ルーチン
Public Sub UpdateShapeTextPreservingStyle(ByVal targetShape As Visio.Shape, ByVal newText As String)
Dim charObj As Visio.Characters
‘ 1. オブジェクトの取得
Set charObj = targetShape.Characters
‘ 2. 現在のテキスト長を取得し、末尾にカーソルを合わせる
‘ Begin/End プロパティを操作することで、部分的な置換や追加が可能
charObj.Begin = charObj.End
‘ 3. 文字列の挿入
‘ ここで挿入された文字は、直前の文字のスタイルを継承する
charObj.Text = newText
‘ 4. 特定の部分だけ色やサイズを変える場合(例:追加したテキストを赤字にする)
Dim startPos As Long
startPos = charObj.Begin
‘ 部分範囲を指定して属性変更
With charObj
.Begin = startPos
.End = startPos + Len(newText)
.CharProps(Visio.VisCellIndices.visCharacterColor) = 2 ‘ 2:赤色(カラーインデックス)
.CharProps(Visio.VisCellIndices.visCharacterSize) = 12 ‘ 12pt
End With
‘ メモリ最適化:オブジェクトの明示的解放
Set charObj = Nothing
End Sub
—
3. ShapeSheet との対話:極限のチューニング
`CharProps`プロパティは便利だが、複雑な条件(例:特定の条件下で太字かつ斜体にする)では、ShapeSheetのセルに直接アクセスする方がパフォーマンス上優位な場合がある。
特に、数千個の図形をループ処理する場合、`Characters`オブジェクトのインスタンス生成を繰り返すと、VBAのガベージコレクションが追いつかず、Visioの描画がスタックする。その際は、`Shape.CellsSRC`を用いたダイレクトアクセスを検討せよ。
‘ ShapeSheetのCharセクションに直接アクセスして書式を強制変更
‘ 速度を優先するバッチ処理においてはこちらが有利
Public Sub FastStyleUpdate(ByVal shp As Visio.Shape)
‘ Charセクションの Size セルを取得
Dim cell As Visio.Cell
Set cell = shp.CellsSRC(Visio.VisSectionIndices.visSectionCharacter, 0, Visio.VisCellIndices.visCharacterSize)
‘ 単位付きの文字列を書き込む(”12pt”など)
cell.FormulaU = “14pt”
Set cell = Nothing
End Sub
—
4. チーフアーキテクトからの助言:レガシー保守の極意
- Undo Scope の活用:
一連のテキスト操作は `Application.BeginUndoScope` で囲むこと。部分書式の変更はUndoスタックを激しく消費する。操作単位を適切に括らなければ、ユーザーは「Ctrl+Z」連打という地獄を見る。
- Window.Invalidate の抑制:
大量の図形を一括更新する場合、ループ内で描画更新が走らないよう `Application.ScreenUpdating = False` を徹底せよ。Visioの描画エンジンは非常に高コストだ。
- API連携の罠:
Windows APIでクリップボード操作を介してテキストを流し込む手法は、書式が崩壊するため「禁じ手」である。APIを呼ぶならば、それはメモリ空間の監視や、外部DBとの同期処理におけるイベントフックに限定すべきだ。
—
結びに代えて
Visio VBAは、GUIツールの顔をしておきながら、その実態は「ShapeSheet」という強力な宣言型データベースを内包した高度な環境だ。`Shape.Text`という安易なプロパティに逃げることは、その強力なデータベースの可能性を自ら捨てることに他ならない。
君が書くコードが、数年後の保守担当者にとっての「呪い」ではなく「羅針盤」となるよう、オブジェクトのライフサイクルを慈しみ、プロパティの背後にあるアーキテクチャを常に意識せよ。
健闘を祈る。
