Visio VBAの限界を超える:DropManyで実現するシェイプ一括転送の極意
業務自動化において、Visioの図面操作を「一つずつコピー&ペーストする」という原始的な手法で止めていないだろうか?
もし君が `Selection.Copy` と `Page.Paste` を繰り返しているなら、今すぐそのコードを捨てるべきだ。それはCPUのサイクルを無駄にするだけでなく、クリップボードという不安定な共有リソースに依存する、極めて脆弱な設計だからだ。
今日は、Visioの描画エンジンを効率的に叩くための「DropManyメソッド」による一括転送術を伝授する。
—
1. なぜ「コピペ」が禁じ手なのか
Visioにおいて `Copy/Paste` は、ユーザー操作を模倣する機能だ。これには以下の致命的な欠点がある。
- クリップボード汚染: 実行中に他のアプリでコピーを行うと、VBAの処理が中断・失敗する。
- パフォーマンスの欠如: 1シェイプごとに描画更新(画面の再描画)が走り、数千単位のシェイプを扱うとフリーズする。
- イベントの暴発: コピーのたびに `ShapeAdded` などのイベントが発火し、意図せぬ連鎖反応を招く。
これに対し、`DropMany` メソッドは、Visioの内部データ構造に対して直接「配置命令」を下す。描画エンジンへの負荷を最小限に抑え、一挙にトランザクションを完了させる、いわば「バルク挿入」の技術だ。
—
2. DropManyによる一括複製の実装
`DropMany` の真骨頂は、シェイプのマスターや既存シェイプの情報を配列で渡し、一度の命令で全オブジェクトを配置することにある。
以下のコードは、ソースページから全シェイプを取得し、ターゲットページへ高速転送するプロトタイプだ。
‘ @brief ソースページからターゲットページへシェイプを一括複製する
‘ @param srcPage 複製元のページ
‘ @param destPage 複製先のページ
Public Sub BatchCopyShapes(srcPage As Visio.Page, destPage As Visio.Page)
Dim srcShapes As Visio.Shapes
Dim count As Long
Dim i As Long
‘ 必要な配列の準備
Set srcShapes = srcPage.Shapes
count = srcShapes.Count
If count = 0 Then Exit Sub
Dim objectsToDrop(1 To 1) As Variant
Dim xyArray() As Double
ReDim xyArray(0 To (count 2) – 1)
‘ 転送用配列の作成
‘ DropManyは、マスターまたはシェイプオブジェクトの配列を受け取る
Set objectsToDrop(1) = srcShapes ‘ 実際には個別のシェイプを指定するケースが多い
‘ 配置座標の計算(ここでは例として全て(1, 1)に置くが、本来は各シェイプのPinX/Yを計算する)
For i = 0 To count – 1
xyArray(i 2) = 1.0 ‘ PinX
xyArray(i 2 + 1) = 1.0 ‘ PinY
Next i
‘ 描画の停止(パフォーマンス向上の鉄則)
Application.ScreenUpdating = False
‘ 一括実行
‘ 第1引数: 配置するオブジェクトの配列, 第2引数: 座標配列
destPage.DropMany srcShapes, xyArray
‘ 描画の再開
Application.ScreenUpdating = True
End Sub
—
3. 現場で生き残るための「堅牢な設計」のポイント
ただコードを動かすだけでは「エンジニア」とは呼べない。実務環境では以下の考慮が不可欠だ。
① 描画の抑制(ScreenUpdating)
`Application.ScreenUpdating = False` を忘れるな。これを怠ると、WindowsのGDIリソースが急激に消費され、OSレベルで動作が重くなる。必ず `Error Handler` を使い、異常終了時にも `True` に戻るよう設計すること。
② 座標変換の罠
`DropMany` は座標を配列で要求する。ソースシェイプの座標をそのまま渡すと、ページ座標系の違いでシェイプが画面外に飛ぶことがある。必ず `srcShape.XYToPage` や `SpatialNeighbors` を使い、正しい位置関係を算出してから配列に格納せよ。
③ データベース連携の注意点
外部データ(ExcelやSQL Server)と連携する場合、シェイプの `ID` をキーにすると痛い目を見る。IDはページ移動やグループ化で容易に変わるからだ。必ず `UniqueID`(VisioのGUID) をプロパティとして保持し、それをキーにマッチングを行うこと。
—
4. チーフアーキテクトからの助言
VisioのVBAは、単なる「自動化ツール」ではない。君が書いたコードは、将来その図面を触る誰かの「設計思想」そのものになる。
- マジックナンバーを排除せよ: ページ名や座標をコードに直書きするな。設定用の定数クラスを作るか、Hiddenなシェイプに設定情報を埋め込む手法を推奨する。
- トランザクションを意識せよ: データの整合性が重要な場合、`Application.BeginUndoScope` と `EndUndoScope` で囲むことで、失敗時に一括でロールバック可能な「安全な処理」を構築できる。
効率化とは、速さだけではない。「壊れないこと」こそが、業務自動化における最高のパフォーマンスだ。
さあ、クリップボードに依存する脆弱なコードを捨て、エンジニアとして「描画エンジンを直接御する」レベルへ到達しよう。君のコードが、組織の生産性を劇的に変えることを期待している。
