こんにちは!Visio VBAの世界へようこそ。
普段の業務で「Visioのマクロを記録してみたら `Copy` や `Paste` が大量に出てきて、実行すると動きが重い…」「100個以上の図形を生成するとフリーズしてしまう」と悩んだことはありませんか?
マクロの記録機能はとても便利ですが、裏側では「Windowsのクリップボード」を経由して愚直にコピー&ペーストを繰り返しています。これは人間が手作業する手順をそのままなぞっているだけで、VBAの潜在能力を10%も活かせていません。
この記事では、マクロ記録の段階を卒業し、「クリップボードを一切汚さず、メモリ上でダイレクトに図形を高速生成・大量複製する極意」を解説します。
Visioオブジェクトモデルの基本を押さえつつ、`Drop` メソッドと `DrawPolyline` メソッドという強力な武器を手に入れましょう。ここをクリアすれば、Visio VBAの基本はバッチリですよ!
—
1. なぜ Copy & Paste は遅いのか?(アンチパターンの裏側)
まずは、なぜ `Copy` / `Paste` が処理を重くし、エラーの原因になるのか、そのメカニズムを簡単に知っておきましょう。
【標準のCopy/Paste(重く不安定)】
VBA ──> Visio UI ──> Windowsクリップボード ──> Visio UI ──> 画面再描画 ──> 描画完了
※ 1回ごとにOSレベルのデータやり取りと画面描画が発生する!
【Drop / DrawPolyline(爆速&安全)】
VBA ──(メモリ上でダイレクト生成)──> Visio内部データ ──> (まとめて1回) ──> 画面再描画
`Selection.Copy` や `Page.Paste` を呼び出すと、内部では次のようなオーバーヘッドが発生しています。
1. Windowsクリップボードのロックとデータ転送:OS全体の共有領域を使用するため、他アプリとの競合や処理待ちが発生します。
2. UIイベントと連携した処理:画面上の選択状態(Selection)をいちいち更新するため、描画負荷が跳ね上がります。
3. OLE/COMオブジェクトの無駄な生成:クリップボード用の中間データがメモリ上に残り、大量ループでメモリを圧迫します。
つまり、「クリップボードを仲介役に使わない」ことこそが、爆速化への第一歩なのです。
—
2. Visioオブジェクトモデルの基本階層をおさらい
図形をメモリ上で直接操作するには、Visioの「誰に命令を出しているのか」を正しく理解する必要があります。
[ Application ] (Visio全体)
│
└── [ Documents ] ── [ Document ] (ファイル / ステンシル)
│
└── [ Pages ] ── [ Page ] (アクティブなページ)
│
└── [ Shapes ] ── [ Shape ] (個々の図形)
- Application:Visioというアプリケーションそのもの。画面更新の停止などを指示します。
- Document:Visioファイル、または「マスターシェイプ」が詰まったステンシル(.vssx)。
- Page:図形を描画するキャンバス。今回の主役です。
- Shape:キャンバス上に配置された図形。
図形を新しく作成するときは、`Page` オブジェクトに対して「ここにこの図形を落として(Drop)」「ここに線を引いて(Draw)」と直接命令を出します。
—
3. 手法①:型(マスター)から爆速複製する `Page.Drop`
既存のシェイプやステンシル内のパーツ(マスターシェイプ)を複製する場合、`Paste` の代わりに `Page.Drop` メソッド を使います。
`Drop` メソッドの使い方
`Page.Drop(ObjectToDrop, xPos, yPos)`
- ObjectToDrop:複製元の `Master` オブジェクト、または既存の `Shape` オブジェクト。
- xPos, yPos:配置する座標(Visioの内部単位はインチなので注意!)。
サンプルコード:Dropを使ったスマートな大量配置
Sub DropExample()
Dim vsoPage As Visio.Page
Dim vsoMaster As Visio.Master
Dim vsoNewShape As Visio.Shape
Dim i As Long
‘ 1. 対象のページを取得
Set vsoPage = ActivePage
‘ 2. ステンシルから「基本形(例: 長方形)」のマスターシェイプを取得
‘ ※ここでは基本ステンシルが既に開かれている前提です
On Error Resume Next
Set vsoMaster = Visio.Documents(“BASIC_M.vssx”).Masters(“Rectangle”)
On Error GoTo 0
If vsoMaster Is Nothing Then
MsgBox “指定のマスターシェイプが見つかりません。”, vbExclamation
Exit Sub
End If
‘ 3. クリップボードを使わずに100個のシェイプを配置
For i = 1 To 100
‘ 座標を少しずつずらしながらDrop (単位: インチ / 1インチ ≒ 25.4mm)
‘ メモリ上で直接生成されるため非常に高速です!
Set vsoNewShape = vsoPage.Drop(vsoMaster, 1.0 + (i 0.1), 5.0)
‘ 生成されたシェイプのテキストを直接書き換える
vsoNewShape.Text = “No.” & i
Next i
MsgBox “100個のシェイプ配置が完了しました!”, vbInformation
End Sub
—
4. 手法②:幾何データから直接描画する `Page.DrawPolyline`
「既存の形を複製するのではなく、データ(座標一覧)から多角形や複雑な線を一括で引きたい」という場合は、`Page.DrawPolyline` メソッド が最強の威力を発揮します。
`DrawPolyline` メソッドの使い方
`Page.DrawPolyline(xyArray, Flags)`
- xyArray:座標 `(X0, Y0, X1, Y1, X2, Y2…)` を格納した `Double` 型の1次元配列。
- Flags:描画オプション(通常は `visPolylinevis` の `0` を指定)。
配列の中にすべての頂点座標を詰めて一気にVisioエンジンへ流し込むため、ループで1本ずつ線を引くのに比べて数十倍〜数百倍速いのが特徴です。
サンプルコード:座標配列から一瞬で図形を描画
Sub DrawPolylineExample()
Dim vsoPage As Visio.Page
Dim vsoShape As Visio.Shape
Dim xyArray() As Double
Set vsoPage = ActivePage
‘ 5点の座標を定義して「星型」などの閉じた多角形を作る準備
‘ (X0, Y0), (X1, Y1), (X2, Y2), (X3, Y3), (X4, Y4), (X0, Y0)
ReDim xyArray(0 To 11) As Double
‘ 座標セット(単位: インチ)
xyArray(0) = 2.0: xyArray(1) = 3.0 ‘ 点1
xyArray(2) = 4.0: xyArray(3) = 3.0 ‘ 点2
xyArray(4) = 4.0: xyArray(5) = 5.0 ‘ 点3
xyArray(6) = 2.0: xyArray(7) = 5.0 ‘ 点4
xyArray(8) = 2.0: xyArray(9) = 3.0 ‘ 始点に戻る(これで閉じた図形になる)
‘ 幾何データをダイレクトに注入してシェイプ化!
Set vsoShape = vsoPage.DrawPolyline(xyArray, 0)
‘ 塗りつぶし色などのスタイルを設定
vsoShape.CellsSRC(visSectionObject, visRowFill, visFillBkgnd).FormulaU = “THEME(” “1” “)”
MsgBox “幾何データからのダイレクト描画が完了しました!”, vbInformation
End Sub
—
5. プロが実践する「極限まで高速化する3つの黄金ルール」
`Drop` や `DrawPolyline` を使うだけでも劇的に速くなりますが、大量処理(数千個レベル)を行う場合は、以下の3つのプロ設定を組み込みましょう。
1. `Application.ScreenUpdating = False`
- 画面の描画更新を止めます。処理中の「チカチカ」がなくなり、速度が倍増します。
2. `Application.DeferRecalc = True`
- Visio内部の数式(ShapeSheet)の再計算を一時停止し、最後にまとめて計算させます。
3. オブジェクト参照の適切な解放(`Set obj = Nothing`)
- ループ内で使った一時オブジェクトは明示的に解放し、メモリリーク(メモリが解放されない現象)を防ぎます。
—
6. 超実践!1,000個のシェイプを爆速生成する完全版コード
それでは、ここまでに学んだ知識をすべて詰め込んだ、実戦用のフルスペックコードをご紹介します。1,000個の図形を生成してもフリーズせず、一瞬で処理が完了する感覚をぜひ体感してください!
Option Explicit
”’
”’
Public Sub CreateThousandShapesFast()
Dim vsoApp As Visio.Application
Dim vsoPage As Visio.Page
Dim vsoMaster As Visio.Master
Dim vsoShape As Visio.Shape
Dim i As Long
Dim startX As Double, startY As Double
Dim currentX As Double, currentY As Double
Dim rowCount As Long, colCount As Long
Dim startTime As Single
‘ 処理時間の計測開始
startTime = Timer
‘ オブジェクトの参照取得
Set vsoApp = Visio.Application
Set vsoPage = vsoApp.ActivePage
‘ ————————————————————-
‘ 黄金ルール1: 再計算と画面更新をOFFにしてパフォーマンスを極限まで上げる
‘ ————————————————————-
vsoApp.ScreenUpdating = False
vsoApp.DeferRecalc = True
On Error GoTo ErrorHandler
‘ サンプル用にビルトインの基本図形(円)をドキュメントから探す
‘ (実務ではご自身のステンシルファイル名・マスター名に変更してください)
Set vsoMaster = GetOrCreateSampleMaster(vsoApp.ActiveDocument)
‘ 配置の初期位置(インチ指定)
startX = 1.0
startY = 10.0
‘ 1,000個のシェイプをグリッド状(20列 × 50行)に配置
For i = 1 To 1000
colCount = (i – 1) Mod 20
rowCount = (i – 1) \ 20
currentX = startX + (colCount 0.35)
currentY = startY – (rowCount 0.35)
‘ ★ここが核心:Copy/PasteではなくDropを使用!
Set vsoShape = vsoPage.Drop(vsoMaster, currentX, currentY)
‘ シェイプ ID をテキストに流し込む(必要最小限の操作)
vsoShape.Text = CStr(i)
‘ メモリを綺麗に保つためループ内で参照を切り離す
Set vsoShape = Nothing
Next i
CleanUp:
‘ ————————————————————-
‘ 黄金ルール2: 必ず設定を元に戻す
‘ ————————————————————-
vsoApp.DeferRecalc = False
vsoApp.ScreenUpdating = True
MsgBox “完了! 処理時間: ” & Format(Timer – startTime, “0.00”) & ” 秒”, vbInformation
Exit Sub
ErrorHandler:
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
Resume CleanUp
End Sub
”’
”’
Private Function GetOrCreateSampleMaster(ByRef doc As Visio.Document) As Visio.Master
On Error Resume Next
Set GetOrCreateSampleMaster = doc.Masters(“DemoCircle”)
On Error GoTo 0
If GetOrCreateSampleMaster Is Nothing Then
‘ マスターが存在しない場合は一時的に作成
Dim tmpShape As Visio.Shape
Set GetOrCreateSampleMaster = doc.Masters.Add
GetOrCreateSampleMaster.Name = “DemoCircle”
Set tmpShape = GetOrCreateSampleMaster.DrawOval(0, 0, 0.25, 0.25)
End If
End Function
—
7. 初心者が陥りやすい罠と対処法(トラブルシューティング)
Visio VBAで `Drop` や `DrawPolyline` を使い始めたときに、よく遭遇するつまずきポイントをまとめました。
罠1:図形が思っている場所に配置されない(座標系の罠)
- 原因:Visioの原点 `(0, 0)` は「ページの左下」にあります。WordやExcel(左上が原点)とは逆なので注意してください。
- 解決策:Y座標は上から下に向かって小さくなるよう計算します(例: `startY – (rowCount 隙間)`)。
罠2:単位がズレる(ミリメートルとインチ)
- 原因:Visio内部の数値表現はすべて「インチ」です。VBAコード内で `1.0` と書くと `1インチ(25.4mm)` として扱われます。
- 解決策:ミリメートル単位で指定したい場合は、コード内で変換関数を用意すると便利です。
Private Function mm2inch(mmValue As Double) As Double
mm2inch = mmValue / 25.4
End Function
罠3:`DrawPolyline` で「インデックスが有効範囲にありません」エラー
- 原因:Visio APIに渡す `Double` 配列の要素数が正しくない(XとYがペアになっていない)場合に発生します。
- 解決策:配列の要素数は必ず「偶数(`0` から始まる場合は奇数のインデックスで終わる)」にしてください。
—
まとめ
今回は、マクロの記録から脱却し、クリップボードを経由しないメモリ効率に優れたシェイプの大量複製手法を解説しました。
- `Copy` / `Paste`:画面描画やOSのクリップボードを挟むため遅く、大量処理でパンクする。
- `Page.Drop`:型(マスター)からダイレクトに生成。高速&確実。
- `Page.DrawPolyline`:座標データから直接描画。多角形や大量ライン描画の最速解。
- 高速化の3つの設定:`ScreenUpdating` と `DeferRecalc` を駆使する。
これらのテクニックを使えば、これまで数分かかっていた図形生成処理がわずか数秒で終わるようになります。
オブジェクトモデルのつながりとメモリへの配慮が理解できれば、Visio VBAの基本はもうバッチリです!ぜひ実際の業務ツールに取り入れて、その圧倒的なスピードを体験してみてくださいね。
