プログラミングの世界へようこそ!Visio VBAの奥深い魅力に足を踏み入れましたね。
「Visioで作成した複雑な図面から、配管レイヤーだけ、あるいは電気系統レイヤーだけを抽出して、高解像度のPNG画像として保存したい…」
こんな作業を手動で何十枚もこなすのは途方もない作業ですし、マウスの選択ミスも起きてしまいます。マクロの記録を使ってみても、レイヤーの選択操作はうまく記録されず、途方に暮れてしまった経験はありませんか?
ご安心ください。Visio VBAには、特定レイヤーの図形を一瞬で束ねて操作する「最強の武器」が備わっています。
今回は、Visioのオブジェクトモデルの本質に触れながら、`Shape.CreateSelection(visSelTypeByLayer)` を使ったスマートなレイヤー一括抽出&高解像度エクスポートの全自動バッチ処理を構築していきましょう。ここをクリアすれば、Visio VBAの基本はバッチリですよ!
—
1. Visio VBAオブジェクトモデルの全貌と「Selection」の秘密
コードを書く前に、Visio内部の「概念の地図」を頭に入れておきましょう。Visio VBAを使いこなす鍵は、オブジェクトの階層構造(オブジェクトモデル)を正しく理解することにあります。
[ Application ] (Visio全体)
│
└── [ Document ] (ファイル)
│
└── [ Page ] (アクティブなページ)
├── [ Layer ] (透明なシートのような概念)
└── [ Selection ] ─── (一括選択されたShapeの集まり)
│
└── [ Shape ] (個々の図形)
通常の自動化では `Page.Shapes` を `For Each` で1つずつループ処理し、「この図形は指定レイヤーに属しているかな?」とチェックしがちです。しかし、図形数が数百〜数千に及ぶと処理が著しく遅くなり、グループ化された図形の内部判定でコードが複雑化してしまいます。
そこで登場するのが `Selection`(選択集合) です。
Visioには、画面上で人間がマウスドラッグして図形を囲む動作を、メモリ上で一瞬にして実行する内部APIが存在します。それが今回主役となる `CreateSelection` メソッドです。
—
2. 魔法のメソッド:CreateSelection(visSelTypeByLayer) とは?
`Page.CreateSelection` メソッドは、指定した条件に合致する図形だけを全自動で集め、1つの `Selection` オブジェクトとして返してくれます。
‘ レイヤー指定で図形を一括選択する基本文法
Set vsoSelection = vsoPage.CreateSelection(visSelTypeByLayer, visSelModeSkipSuper, vsoLayer)
引数の解説
1. `visSelTypeByLayer` (第1引数): 選択タイプ。「レイヤーを基準にして選択する」という宣言です。
2. `visSelModeSkipSuper` (第2引数): 選択モード。グループ図形が存在する場合、内部の個別図形ではなくグループの親階層をスマートに扱ってくれるフラグです。
3. `vsoLayer` (第3引数): 対象となる `Layer` オブジェクトを指定します。
この1行を実行するだけで、ミリ秒単位で目的のレイヤー上の図形だけが「選択状態」になります。あとは、その `Selection` オブジェクトに対して `.Export` を命じるだけで、目的の画像が吐き出される仕組みです。
—
3. 実践コード:指定レイヤーの一括抽出&高解像度エクスポート
それでは、実際に動くフルコードを見てみましょう。
標準モジュールに以下のコードを貼り付けて実行できるように設計してあります。プロの現場でもそのまま耐えうるよう、エラーハンドリングと描画最適化(画面更新の停止)を組み込んでいます。
Option Explicit
”
‘ Visio VBA: 特定レイヤーの図形を一括選択し高解像度PNGとしてエクスポートするバッチ処理
‘
Public Sub ExportSpecificLayerToImage()
‘ — オブジェクト変数の宣言 —
Dim vsoDoc As Visio.Document
Dim vsoPage As Visio.Page
Dim vsoLayer As Visio.Layer
Dim vsoSelection As Visio.Selection
‘ — 設定値の定義 —
Dim targetLayerName As String
Dim exportFilePath As String
Dim i As Long
Dim layerFound As Boolean
‘ 抽出したいレイヤー名と出力先を指定します
targetLayerName = “電気設備” ‘ ←ここに対象のレイヤー名を入力
exportFilePath = CurrentProjectFolderPath() & “\” & targetLayerName & “_Export.png”
‘ — 処理の開始とパフォーマンス最適化 —
‘ 描画更新をオフにして処理速度を爆発的に向上させます
Visio.Application.ScreenUpdating = False
On Error GoTo ErrorHandler
Set vsoDoc = Visio.ActiveDocument
Set vsoPage = Visio.ActivePage
‘ 1. 対象のレイヤーが存在するかチェックして取得
layerFound = False
For i = 1 To vsoPage.Layers.Count
If vsoPage.Layers(i).Name = targetLayerName Then
Set vsoLayer = vsoPage.Layers(i)
layerFound = True
Exit For
End If
Next i
‘ レイヤーが見つからない場合は安全に終了
If Not layerFound Then
MsgBox “指定されたレイヤー ‘” & targetLayerName & “‘ がページ内に見つかりませんでした。”, _
vbExclamation, “処理中断”
GoTo CleanUp
End If
‘ 2. 【核心部】CreateSelectionを使ってレイヤー内の図形を一括選択!
‘ 画面を非表示のまま、メモリ上で瞬時に選択範囲を作成します
Set vsoSelection = vsoPage.CreateSelection(visSelTypeByLayer, visSelModeSkipSuper, vsoLayer)
‘ 選択された図形が存在するか確認
If vsoSelection.Count = 0 Then
MsgBox “レイヤー ‘” & targetLayerName & “‘ には配置されている図形がありません。”, _
vbInformation, “情報”
GoTo CleanUp
End If
‘ 3. 選択された図形群だけを画像ファイルとしてエクスポート
‘ SelectionオブジェクトのExportメソッドは選択中の図形の外形サイズで自動切り出します
vsoSelection.Export exportFilePath
MsgBox “エクスポートが完了しました!” & vbCrLf & “保存先: ” & exportFilePath, _
vbInformation, “成功”
CleanUp:
‘ — 後処理(メモリ解放と画面更新の再開) —
Visio.Application.ScreenUpdating = True
Set vsoSelection = Nothing
Set vsoLayer = Nothing
Set vsoPage = Nothing
Set vsoDoc = Nothing
Exit Sub
ErrorHandler:
‘ エラーが発生した場合も必ずScreenUpdatingを戻す
Visio.Application.ScreenUpdating = True
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “エラー”
Resume CleanUp
End Sub
”
‘ 補助関数: アクティブドキュメントの保存先フォルダパスを取得する
‘
Private Function CurrentProjectFolderPath() As String
If Visio.ActiveDocument.Path = “” Then
‘ ドキュメントが未保存の場合はCドライブ直下などに退避
CurrentProjectFolderPath = “C:\Temp”
Else
‘ 末尾の円マークを取り除いたパスを返す
CurrentProjectFolderPath = Left(Visio.ActiveDocument.Path, Len(Visio.ActiveDocument.Path) – 1)
End If
End Function
—
4. プロの知見:コードの深掘り解説
上記のコードには、マクロの記録から脱却し、実務でトラブルを起こさないためのノウハウが詰まっています。ポイントを深掘りしてみましょう。
① なぜ `Layers(“レイヤー名”)` で直接取得しないのか?
Visioの仕様上、`vsoPage.Layers.Item(“レイヤー名”)` で取得しようとすると、万が一そのレイヤーが存在しなかった場合に実行時エラー(例外)が直接発生してプログラムが停止します。
そのため、コード内では `For i = 1 To vsoPage.Layers.Count` で安全にループを回し、名前の一致を確認する「防御的プログラミング」を採用しています。
② `vsoSelection.Export` の挙動
`Page.Export` を使うと「ページ全体」が画像化されてしまいますが、`Selection.Export` を使うと「選択された図形群がぴったり収まるバウンディングボックス(外枠)のサイズ」で透過画像(PNG等)が切り出されます。
余計な余白が含まれない美しく締まった画像が出力できるのが、`Selection` を経由する最大のメリットです。
③ `ScreenUpdating = False` による高速化
Visio VBAで最も処理時間を消費するのは「画面の再描画(レンダリング)」です。
選択状態を作る前に `Application.ScreenUpdating = False` に設定しておくことで、ユーザーの画面をちらつかせることなく、裏で静かにミリ秒単位の高速処理を実行できます。
—
5. 初心者が陥りやすい3つの罠と解決策(トラブルシューティング)
Visio VBAを扱い始めた方が必ずと言っていいほど直面する壁と、その回避方法をお伝えします。
罠1:画像のエクスポート解像度が低くて文字が滲む
`Selection.Export` は、デフォルトではモニターの画面解像度(96 DPI程度)で出力されることがあります。印刷や拡大表示に耐えうる高解像度で出力したい場合は、事前にVisioのレジストリやエクスポート設定ダイアログの初期値を設定するか、以下のように描画品質を維持する工夫が必要です。
罠2:非表示レイヤーの図形が選択・エクスポートできない
レイヤーの「表示」チェックボックスがオフになっていると、`CreateSelection` で選択対象から外れる場合があります。確実にエクスポートしたい場合は、選択直前に一時的にレイヤーを表示状態にするコードを追加しましょう。
‘ レイヤーを一時的に表示状態にする
vsoLayer.CellsC(visLayerVisible).FormulaU = “1”
罠3:グループ化された図形の一部だけレイヤーに属している
親図形は「無所属」なのに、グループの中の子供の図形だけが「特定レイヤー」に所属している複雑な図面が存在します。
このとき、`CreateSelection` の第2引数に `visSelModeSkipSuper` を指定しておけば、Visioが適切に親グループを含めて解釈してくれるため、画像が虫食い状に欠けるトラブルを防止できます。
—
6. まとめと次のステップ
今回は、Visio VBAの根幹をなす 「Application ➔ Document ➔ Page ➔ Layer ➔ Selection ➔ Shape」 の関係性を学び、`CreateSelection` を使ったレイヤー単位のスマートな画像抽出バッチを構築しました。
1. `For Each` で図形を1つずつ調べるのは卒業し、`CreateSelection` で一瞬で束ねる
2. `Page.Export` ではなく `Selection.Export` を使うことで、余白のない完璧なトリミング画像を得る
3. `ScreenUpdating` の制御と安全なレイヤー探索で、プロ品質の堅牢性を確保する
ここをクリアすれば、Visio VBAの基礎はバッチリですよ!
次は、この処理を応用して「全ページを巡回してレイヤー別にフォルダ分け出力する完全自動化バッチ」や、「Excelのリストと連動してレイヤーの表示・非表示を一元管理するツール」などに挑戦してみてください。あなたの業務効率化の可能性は、どこまでも広がっています!
