Visio図面が、なぜか「重い」と感じたことはありませんか?
開くのに時間がかかったり、保存に手間取ったり…。それはまるで、知らない間に図面ファイルが余分な荷物を抱え込んでしまっているようなものです。
皆さん、こんにちは!世界最高峰の業務自動化エンジニアにして、Visio VBAを知り尽くしたチーフアーキテクト、〇〇(あなたの名前)です。今日は、そんな「重いVisio図面」の根本原因の一つにメスを入れ、ファイルサイズを劇的に改善するVisio VBAの秘技をお伝えします。
今回のテーマは、「Visio図面を保存する際、ファイルサイズを圧縮するための不要なステンシル(マスターシェイプ)削除処理」です。
プログラミング初学者の方も、マクロの記録から一歩踏み出したい方もご安心ください。Visioのオブジェクトモデルの核心に触れつつ、なぜこの処理が必要なのか、そしてどうVBAで実現するのかを、優しく、そして本質的に解説していきます。ここをクリアすれば、Visio VBAの基本はバッチリですよ!
なぜVisio図面は肥大化するのか?「マスターシェイプ」の闇
Visioを使っていると、いつの間にかファイルサイズが大きくなっていることがありますよね。図面がシンプルに見えても、その裏側には知られざる「荷物」が隠されていることが少なくありません。その代表格が、今回の主役である「マスターシェイプ」です。
「マスターシェイプ」とは何か?
Visioの図面では、私たちがキャンバスに配置する一つ一つの図形を「シェイプ」と呼びます。そして、このシェイプの「元となるひな形」が「マスターシェイプ」です。
想像してみてください。あなたは工場で大量生産される製品の設計図を作成しています。
- ステンシル: 製品カタログのようなもので、様々な製品(マスターシェイプ)が一覧で並んでいます。
- マスターシェイプ: カタログに載っている個々の製品の「設計図」そのものです。色、形、動作の仕様など、全ての情報が詰まっています。
- シェイプ: 設計図(マスターシェイプ)に基づいて実際に工場で生産され、キャンバスに配置される「製品」です。
つまり、キャンバスに配置したシェイプは、すべてどこかのマスターシェイプを参照して作られている、という関係性があります。
なぜ使っていないマスターが残るのか?その「負の遺産」
「でも、使ってないなら勝手に消えてくれるんじゃないの?」
そう思われるかもしれません。しかし、Visioは残念ながらそこまで賢くありません。以下のようなシナリオで、不要なマスターシェイプが図面ファイル内に温存されがちです。
1. 「とりあえず貼り付け」の罠: 別のVisio図面やWebサイト、Wordなどからシェイプをコピー&ペーストした場合、そのシェイプが参照しているマスターシェイプも、図面ファイル内に「持ち込まれて」しまいます。たとえすぐにそのシェイプを削除したとしても、持ち込まれたマスターシェイプは残ってしまうことが多いのです。
2. 昔使ったシェイプの名残: 以前は使っていたけれど、もう不要になったシェイプを削除しても、そのマスターシェイプが図面から自動的に削除されることはありません。
3. グループ化されたシェイプの解除: 複雑なグループシェイプを解除すると、その内部で使われていたマスターが図面に残ることがあります。
これらの「負の遺産」は、使われていないにもかかわらず、図面ファイルの中にメタデータやプレビュー画像などの形で存在し続けます。これが積もり積もって、ファイルサイズを不用意に肥大化させる原因となるのです。
ファイルサイズ最適化は「Visioの健康管理」だ!
図面ファイルが軽くなることには、多くのメリットがあります。
- 開閉速度・保存速度の向上: ストレスなく作業が進められます。
- ネットワーク転送速度の向上: 大容量ファイル送信時のイライラが解消されます。
- 共有・管理のしやすさ: 他の人との共同作業や、バージョン管理がスムーズになります。
手作業で一つ一つのマスターシェイプを確認し、削除するのは現実的ではありません。そこで、Visio VBAの出番です!VBAを使えば、この面倒な作業を一瞬で終わらせることができます。
いざ実践!不要なマスターシェイプを駆逐するVBAスクリプト
さあ、いよいよ本丸です。Visio VBAの力を借りて、図面をクリーンアップしましょう。
ステップ1: 開発タブの表示とVBAエディタの起動
まだ「開発」タブが表示されていない場合は、以下の手順で表示させてください。
1. Visioの「ファイル」タブをクリック。
2. 「オプション」をクリック。
3. 「リボンのユーザー設定」をクリック。
4. 右側の「リボンのユーザー設定」リストで「開発」にチェックを入れ、「OK」をクリック。
「開発」タブが表示されたら、「Visual Basic」をクリックしてVBAエディタを起動します。
ステップ2: VBAコードの貼り付け
VBAエディタが開いたら、左側の「プロジェクトエクスプローラー」ペインで、現在開いているVisio図面(通常は「VBAProject (<ファイル名>.vsdx)」)を展開し、「Microsoft Visio オブジェクト」の下にある「ThisDocument」をダブルクリックします。
開いたコードウィンドウに、以下のコードをそのままコピー&ペーストしてください。
Sub CleanUpUnusedMasters()
‘
‘ プロシージャ名: CleanUpUnusedMasters
‘ 機能: Visio図面内の未使用のマスターシェイプを削除し、ファイルサイズを最適化します。
‘ 対象: アクティブなVisioドキュメント
‘ 備考: 削除されたマスターは元に戻せません。実行前に必ずバックアップを取ってください。
‘
‘ 処理中にVisioの画面更新を一時停止します。
‘ これにより、処理速度が向上し、画面のちらつきを抑えられます。
Application.ScreenUpdating = False
‘ エラーが発生してもVBAが停止しないように設定します。
‘ ただし、これは簡易的なエラーハンドリングであり、本格的な運用では
‘ エラーの種類に応じた詳細なハンドリングを実装することを推奨します。
On Error Resume Next
Dim doc As Visio.Document
‘ 現在アクティブになっているVisioドキュメントオブジェクトを取得します。
Set doc = Application.ActiveDocument
‘ もしアクティブなドキュメントが存在しない場合、メッセージを表示して処理を終了します。
If doc Is Nothing Then
MsgBox “開いているVisioドキュメントがありません。処理を中断します。”, vbExclamation
Application.ScreenUpdating = True ‘ 画面更新を再開
Exit Sub
End If
Dim masterCountBefore As Long ‘ 処理前のマスターシェイプ総数を格納する変数
Dim masterCountAfter As Long ‘ 処理後のマスターシェイプ総数を格納する変数
Dim deletedCount As Long ‘ 削除されたマスターシェイプの数をカウントする変数
deletedCount = 0 ‘ 初期化
‘ 処理開始前のマスターシェイプの数を記録します。
masterCountBefore = doc.Masters.Count
‘ — ここからが、不要なマスターシェイプを特定し削除する核心です! —
Dim mst As Visio.Master ‘ 各マスターシェイプを一時的に保持するオブジェクト変数
Dim i As Long ‘ ループカウンタ
‘ Mastersコレクション(図面内の全マスターシェイプの集合)を逆順にループします。
‘ 要素をコレクションから削除すると、残りの要素のインデックスがずれるため、
‘ 後ろから前にループするのが安全なプログラミングプラクティスです。
For i = doc.Masters.Count To 1 Step -1
‘ i番目のマスターシェイプを取得します。
Set mst = doc.Masters.Item(i)
‘ Master.Referenced プロパティがこの処理の鍵です。
‘ このプロパティが True の場合、そのマスターは図面上のどこかのシェイプから参照されています。
‘ False の場合、どこにも参照されていない「孤立した」マスターです。
If Not mst.Referenced Then ‘ もしこのマスターがどこからも参照されていなければ(=不要なマスターであれば)
On Error Resume Next ‘ 削除処理中にエラーが発生しても、次のマスターに進むように設定
mst.Delete ‘ そのマスターシェイプを削除します。
If Err.Number = 0 Then ‘ エラーなく削除できた場合
deletedCount = deletedCount + 1 ‘ 削除カウントを増やす
Else
‘ 何らかの理由で削除できなかったマスターがあった場合、デバッグウィンドウに警告を出力します。
‘ 例: マスターが保護されている、Visio内部的なロックなど。
Debug.Print “Warning: マスター ‘” & mst.NameU & “‘ の削除に失敗しました。エラー: ” & Err.Description
End If
On Error GoTo 0 ‘ エラーハンドリングをデフォルトに戻します(次のループのために)
End If
Next i
‘ 処理終了後のマスターシェイプの数を記録します。
masterCountAfter = doc.Masters.Count
‘ ユーザーに処理結果をメッセージボックスで通知します。
MsgBox “Visio図面内の不要なマスターシェイプのクリーンアップが完了しました!” & vbCrLf & _
“————————————————-” & vbCrLf & _
“削除前マスター数: ” & masterCountBefore & vbCrLf & _
“削除後マスター数: ” & masterCountAfter & vbCrLf & _
“削除されたマスター数: ” & deletedCount & vbCrLf & _
“————————————————-” & vbCrLf & _
“これで図面ファイルがスリムになり、快適に作業できますよ!”, vbInformation
‘ 処理中に停止していた画面更新を再開します。
Application.ScreenUpdating = True
‘ オブジェクト変数を解放し、メモリをクリーンアップします。
Set mst = Nothing
Set doc = Nothing
End Sub
ステップ3: コード解説 – 知るべきは「オブジェクトのライフサイクル」と「参照」の本質
貼り付けたコードを、一つずつ丁寧に解説していきましょう。
`Application.ScreenUpdating = False` の意味
これはVisio VBAにおけるパフォーマンスチューニングの基本中の基本です。
VBAがVisioの操作を行うたびに画面が更新されると、そのたびに描画処理が発生し、非常に時間がかかります。この設定を`False`にすることで、VBAがバックグラウンドで処理を進め、最後に一度だけ画面を更新するため、処理が劇的に速くなります。まるで、プロの職人が周りを気にせず集中して作業をこなすようなものです。
`ActiveDocument` オブジェクト
`Set doc = Application.ActiveDocument`
`Application`はVisioアプリケーション全体を表すオブジェクトです。その中で`ActiveDocument`は「現在開いていて、アクティブになっている図面ファイル」を指します。今回の処理の対象となる図面を特定するための出発点ですね。
`Masters` コレクション
`doc.Masters`
これは、現在開いている図面ファイル内に存在する、すべてのマスターシェイプの集合体(コレクション)です。VBAでは、このような「同じ種類のオブジェクトの集まり」をコレクションとして扱います。
`Master` オブジェクト
`Dim mst As Visio.Master`
`Set mst = doc.Masters.Item(i)`
`Master`は、`Masters`コレクションの中の個々のマスターシェイプを表すオブジェクトです。この`mst`変数を使って、個々のマスターシェイプの情報を取得したり、操作したりします。
`Master.Referenced` プロパティの真髄
`If Not mst.Referenced Then`
ここが今回のスクリプトの心臓部であり、Visioのオブジェクトのライフサイクルを理解する上で最も重要なポイントです。
`Master.Referenced`プロパティは、そのマスターシェイプが「現在、Visio図面上のいずれかのシェイプから参照されているか」を示すブール値(True/False)を返します。
- `True` の場合: 図面上のどこかに、このマスターを元にして作られたシェイプが存在します。つまり、このマスターは「現役」であり、削除してはいけません。
- `False` の場合: 図面上のどのシェイプからも参照されていません。これが「不要なマスターシェイプ」の正体です。
Visioは内部的に、各マスターシェイプがいくつ参照されているかを管理する「参照カウンタ」のような仕組みを持っています。`Referenced`プロパティは、このカウンタがゼロかどうかを教えてくれている、とイメージすると分かりやすいでしょう。オブジェクトのライフサイクルにおいて、参照がゼロになったオブジェクトは「役目を終えた」と判断されるわけです。
`Master.Delete` メソッド
`mst.Delete`
`Referenced`が`False`と判断されたマスターシェイプに対して、このメソッドを実行することで、図面ファイルからそのマスターシェイプを完全に削除します。
`Delete`メソッドは、単にリストから消すだけでなく、Visioの内部データ構造からそのマスターシェイプに関する情報を解放し、メモリ上からもきれいに消え去るよう作用します。まさに、不要な荷物を完全に捨て去るイメージです。
`For i = doc.Masters.Count To 1 Step -1` の理由
「なぜ、後ろから前にループするんだろう?」
これは、コレクションから要素を削除する際のVBAの鉄則です。
例えば、10個のマスターがあるとして、前から順番に削除していくとどうなるでしょう?
1番目を削除すると、もともと2番目だったものが新しい1番目になり、インデックスがずれてしまいます。その結果、本来処理すべきマスターがスキップされてしまったり、エラーが発生したりする可能性があるのです。
しかし、後ろから削除していけば、たとえ途中の要素が削除されても、それより前のインデックスには影響がないため、安全かつ確実にすべての要素を処理できます。これはコレクションを操作する上での黄金律なので、ぜひ覚えておいてください。
エラーハンドリング `On Error Resume Next` の優しさと厳しさ
`On Error Resume Next`は、VBAでエラーが発生しても処理を中断せず、次の行にスキップして実行を続ける命令です。
今回のスクリプトでは、特定のマスターが何らかの理由(例えば、Visio内部でロックされているなど)で削除できない場合に、処理全体が止まってしまわないように、削除命令の直前に置いています。
これは初学者にとっては非常に便利な機能ですが、諸刃の剣でもあります。エラーを無視することで、問題が隠蔽されてしまい、デバッグが困難になる可能性もあります。本格的な開発では、`On Error GoTo`などを使って、エラーの種類に応じて適切な処理(ログ記録、ユーザーへの通知など)を行うのがベストプラッグチスです。今回は「まずは動かしてみる」という目的でシンプルに導入しました。
知っておきたい高度な考慮事項と注意点
素晴らしい!これであなたのVisio図面は、余分な脂肪をそぎ落としてスリムになったはずです。しかし、VBAの力を扱う上で、いくつか心に留めておいてほしいことがあります。
「削除」は不可逆!必ずバックアップを!
VBAで実行された削除処理は、Visioの「元に戻す(Ctrl+Z)」機能では取り消せません。まさに「元には戻せない」操作です。
そのため、このスクリプトを実行する前には、必ず図面ファイルのバックアップを取るようにしてください。これは、VBAに限らず、重要なデータを扱う自動化処理の鉄則です。
`Referenced` プロパティの稀な挙動
`Master.Referenced`プロパティは非常に信頼性が高いですが、Visioの複雑な内部構造や、特定の条件下では、ごく稀に意図しない結果を示すことがあります。例えば、非常に特殊な方法で図形データに埋め込まれたマスターや、破損したファイルの場合などです。
しかし、一般的な用途であれば、このプロパティを信頼して問題ありません。もし削除してはいけないものが消えてしまった場合は、バックアップから復元してください。
リンクされた図面やオブジェクトへの影響
今回のスクリプトは、あくまで「現在のVisioドキュメント内に存在する、使われていないマスターシェイプ」のみを対象としています。
もし図面内に、外部のファイルにリンクされているオブジェクトや、埋め込まれた外部ファイル(Word文書など)がある場合、それらの中のマスターには影響を与えません。それらをクリーンアップするには、それぞれのアプリケーションでの処理が必要になります。
`Master.Delete` が失敗するケース
前述の通り、`Master.Delete`がエラーになる場合があります。主な理由は以下の通りです。
- マスターが保護されている: 特定のステンシルやアドオンによって、マスターが編集・削除から保護されている場合があります。
- Visio内部的なロック: Visioのセッション中に一時的にロックされているマスターなど。
これらのケースでは、`On Error Resume Next`のおかげで処理は止まりませんが、削除されたマスター数にはカウントされません。`Debug.Print`で出力される警告メッセージを参考に、必要であれば手動で対応を検討してください。
まとめ: あなたのVisio図面はきっと喜びます!
いかがでしたでしょうか?
今回は、Visio図面が肥大化する原因の一つである「不要なマスターシェイプ」に焦点を当て、Visio VBAを使って効率的にクリーンアップする方法を学びました。
- Visioの「マスターシェイプ」が図面の構成要素のひな形であること。
- 使われなくなったマスターシェイプがファイルサイズを肥大化させる原因となること。
- `Master.Referenced`プロパティで不要なマスターを特定し、`Master.Delete`で削除するVBAの仕組み。
- コレクションを逆順にループする重要性や、パフォーマンスチューニングの基本。
これらの知識は、Visio VBAを深く理解するための第一歩です。オブジェクトのライフサイクルや参照の概念は、他のプログラミング言語でも非常に重要となる基礎的な考え方ですよ。
今回のスクリプトをマスターすれば、あなたのVisio図面は常にスリムで、パフォーマンスの高い状態を保つことができるでしょう。まるで、優秀な秘書が常にデスクを整理整頓してくれるようなものです。
ここをクリアすれば、Visio VBAの基本はバッチリですよ!
さらに踏み込んで、例えば「図面を保存するたびに自動でこのクリーンアップ処理を実行する」といった高度な自動化にも挑戦できます。それは`Document.BeforeDocumentSave`イベントという、Visio VBAのさらに奥深い世界への扉を開くことになります。
Visio VBAの世界は奥深く、探求すればするほど、あなたの業務を劇的に効率化する可能性を秘めています。これからも一緒に、その極限の知見を追求していきましょう!
