【入門編】Shape.CreateSelection(visSelTypeByLayer)を活用したレイヤー単位の一括選択と画像エクスポート – Visio VBA解析バイブル

スポンサーリンク

プログラミングの世界へようこそ!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のリストと連動してレイヤーの表示・非表示を一元管理するツール」などに挑戦してみてください。あなたの業務効率化の可能性は、どこまでも広がっています!

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