Visioを「フリーズ」させない:数千シェイプを掌握する進捗表示の極意
業務自動化の現場でVisioを扱うとき、多くのエンジニアが直面する壁がある。「数百ページの図面、数千のシェイプを処理するとVisioが応答なし(Not Responding)になる」という問題だ。
これを「Visioの仕様だから仕方ない」と諦めていないか?
それは甘えだ。ユーザーにとって、処理中にアプリがフリーズすることは「バグっている」のと同義である。今回は、Visio VBAの内部構造を理解し、洗練された進捗表示を実装する「プロの作法」を伝授する。
—
1. なぜ「フリーズ」が起きるのか?
Visioのレンダリングエンジンは、単一スレッドで動作している。VBAで`Shapes`コレクションをループさせ、色を変えたりテキストを流し込んだりすると、Visioのメインループは「描画更新」という優先順位の高いタスクを後回しにする。その結果、OSは「このアプリは固まった」と判断し、タイトルバーに「応答なし」を表示する。
これを防ぐ鍵は、「メインループを強制的に解放し、OSに描画と入力を委譲する」こと。これが`DoEvents`の真髄だ。
—
2. 堅牢な進捗表示の実装パターン
ただ`DoEvents`を叩けばいいわけではない。過度な呼び出しはパフォーマンスを著しく低下させる。「1%進むごとに更新する」といった適切な粒度で制御するのが、ハイパフォーマンスなツール開発の定石だ。
プロダクション環境に耐えうる実装例
このコードは、処理対象のシェイプ数を事前にカウントし、ステータスバーを更新しつつ、描画負荷を最小限に抑える設計となっている。
‘ @description: 大容量処理における進捗表示付きシェイプ処理のテンプレート
Public Sub ProcessShapesWithProgress()
Dim shp As Visio.Shape
Dim pg As Visio.Page
Dim totalShapes As Long
Dim currentCount As Long
Dim lastPercent As Integer
‘ 1. 事前カウント(パフォーマンスのため、一度だけ実行)
totalShapes = GetTotalShapeCount()
‘ 2. ステータスバーの初期化
Application.StatusBar = “処理を開始しています…”
For Each pg In ActiveDocument.Pages
For Each shp In pg.Shapes
‘ — ここに本来の処理を記述 —
‘ 例: shp.Cells(“FillForegnd”).Formula = “RGB(255,0,0)”
‘ —————————–
currentCount = currentCount + 1
‘ 3. 進捗の更新(1%刻みで実行することでオーバーヘッドを抑制)
Dim currentPercent As Integer
currentPercent = Int((currentCount / totalShapes) 100)
If currentPercent > lastPercent Then
Application.StatusBar = “進捗: ” & currentPercent & “% (” & currentCount & “/” & totalShapes & “)”
DoEvents ‘ ここでOSに制御を戻し、描画と入力を受け付ける
lastPercent = currentPercent
End If
Next shp
Next pg
Application.StatusBar = “完了しました。”
End Sub
Private Function GetTotalShapeCount() As Long
‘ 処理対象の全シェイプ数を取得するロジック
Dim count As Long
‘ 省略:各ページのShapes.Countを合計する処理
GetTotalShapeCount = count
End Function
—
3. 実務で「陥りがちな罠」への対策
1. `DoEvents`の悪用を防げ
`DoEvents`は便利だが、魔法ではない。ループの1回ごとに実行すれば、処理速度は劇的に低下する。前述の通り、「`lastPercent`」という変数で前回更新時と比較し、変化があったときだけ叩くのが、計算コストとユーザー体験の黄金比だ。
2. データベース・ファイル連携時の注意
Visioから外部データ(ExcelやDB)を読み書きしながら処理する場合、`DoEvents`中にユーザーが「閉じる」ボタンを押す可能性がある。このとき、未保存のDB接続やファイルハンドルが残るとメモリリークやデータの不整合を招く。
- 対策: `Global`変数等で「処理中フラグ」を立て、処理完了までユーザーの操作を制限するか、`Try-Catch`相当の例外処理(`On Error Resume Next`を適切に活用したエラーハンドリング)を必ず実装すること。
3. ステータスバーの「後始末」
`Application.StatusBar`は、処理終了後に必ず空文字に戻すか、`False`(Visioの自動制御に戻す)に設定すること。これを忘れると、ユーザーは「永遠に処理中」という不安を抱えたままVisioを使い続けることになる。
—
4. 最後に:アーキテクトからの助言
ツール開発において、コードが動くことは「スタート地点」に過ぎない。
本当に優れた自動化ツールとは、「ユーザーにストレスを与えず、あたかもVisioに元から備わっている機能であるかのように振る舞うもの」だ。
`DoEvents`を使いこなすということは、君がマシンの計算リソースと、ユーザーの心理的リソースの両方をコントロールする指揮官になるということだ。ぜひ、この実装を自身のツールに組み込み、ワンランク上のエンジニアリングを見せてほしい。
質問があればいつでも歓迎する。ただし、基本動作を理解した上で、更なる最適化を求める者のみに限定させてもらう。
