【CorelDRAW VBAを掌握する極限の知見】特定図形を全ページから即座に狩り出す「オブジェクト検索&ページジャンプ」の極意
大規模なマルチページ・ドキュメントを相手にする時、エンジニアが直面する最大のストレスは「エラーを内包した特定のオブジェクト」や「特定のメタデータを持つ図形」が、ドキュメントのどこに潜んでいるのかを目視で探す徒労感である。
CorelDRAWのGUIは優れているが、数千ページ、あるいは複雑なレイヤー階層が入り組んだドキュメントにおいて、特定のシェイプを全ページ走査してフォーカスする処理を素朴に実装すると、メモリリークや画面のチラつき、最悪の場合はCOM例外によるクラッシュを引き起こす。
今回は、CorelDRAW VBAのオブジェクトモデルの深淵を暴き、「特定の条件に一致するオブジェクトを全ページから高速に特定し、一瞬でそのページへ画面をジャンプさせるデバッグエンジン」の構築手法を、実戦投入可能なコードとともに解説する。
—
1. CorelDRAW VBAアーキテクチャの暗黙の罠
まず、CorelDRAWのドキュメント構造(DOM)の特性を理解しなければならない。
`ActiveDocument.Pages` コレクションを安易にループさせ、各ページの `Layers`、そして `Shapes` を再帰的に探索するコードは、一見正しく動くように見える。しかし、以下の2点を見落とすと実用に耐えない。
1. 画面描画(ScreenUpdating)のオーバーヘッド:ページを切り替えるたびにCorelDRAWのGUIが再描画を行われ、実行速度が致命的に低下する。
2. オブジェクト参照のライフサイクル:VBAのCOMラッパーは、適切に参照を解放しないと内部メモリ上にゾンビオブジェクトが残り、CorelDRAW自体の動作を不安定にする。
これを克服するため、検索フェーズでは画面描画を完全に停止し、純粋なメモリ上のDOM走査のみを行わせる。そして、目的のオブジェクトを発見した瞬間のみ、ビューポートをターゲットページに切り替える。
—
2. 実装コード:全ページ高速検索&ジャンプエンジン
以下のコードは、指定したテキスト(またはシェイプ名・条件)を全ページから逆引きし、該当ページへ瞬時にジャンプ、さらに該当オブジェクトを選択状態にしてズームする実用プロシージャである。
Option Explicit
‘ Win32 API: 処理中の画面描画抑制による爆速化(必要に応じて活用)
If VBA7 Then
Private Declare PtrSafe Sub Sleep Lib “kernel32” (ByVal dwMilliseconds As Long)
Else
Private Declare Sub Sleep Lib “kernel32” (ByVal dwMilliseconds As Long)
End If
Public Sub FindObjectAndJumpPage()
Dim targetText As String
targetText = InputBox(“検索するテキスト(部分一致)を入力してください:”, “オブジェクト検索エンジン”, “ERROR”)
If Trim(targetText) = “” Then Exit Sub
Dim doc As Document
Set doc = Application.ActiveDocument
If doc Is Nothing Then
MsgBox “アクティブなドキュメントが存在しません。”, vbCritical, “致命的エラー”
Exit Sub
End Sub
‘ —————————————————————–
‘ 極限のパフォーマンス最適化:画面描画とイベントの完全凍結
‘ —————————————————————–
Application.Optimization = True
doc.BeginCommandGroup
Dim found As Boolean
found = False
Dim targetPage As Page
Dim targetShape As Shape
Dim p As Page
Dim s As Shape
On Error GoTo ErrorHandler
‘ 全ページを走査
For Each p In doc.Pages
‘ パフォーマンスのため、非表示ページはスキップ等の条件分岐を入れてもよい
‘ ページ内の全シェイプを走査(グループ化されたオブジェクトやレイヤーを跨ぐ)
Set targetShape = SearchShapeRecursive(p.Shapes, targetText)
If Not targetShape Is Nothing Then
Set targetPage = p
found = True
Exit For ‘ 最初に見つかった時点でループを抜ける(全件検索する場合はコレクションに格納)
End If
Next p
‘ —————————————————————–
‘ 復元処理
‘ —————————————————————–
doc.EndCommandGroup
Application.Optimization = False
Application.Refresh
‘ 結果の判定とジャンプ実行
If found Then
‘ 該当ページをアクティブにする
targetPage.Active = True
‘ 画面のビューポートを該当オブジェクトにジャンプ(ズーム)
ActiveWindow.ActiveView.ToFitShape targetShape
‘ 該当オブジェクトを選択状態にする
targetShape.CreateSelection
MsgBox “オブジェクトを発見しました!” & vbCrLf & _
“ページ番号: ” & targetPage.Index & vbCrLf & _
“シェイプ名: ” & targetShape.Name, vbInformation, “検索成功”
Else
MsgBox “指定された条件に一致するオブジェクトは発見されませんでした。”, vbExclamation, “検索結果”
End If
Exit Sub
ErrorHandler:
‘ 異常終了時の安全装置:必ず最適化フラグを戻す
Application.Optimization = False
doc.EndCommandGroup
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “システムエラー”
End Sub
‘ ———————————————————————
‘ 再帰的シェイプ検索関数(グループ化・コンポーネント内部まで透過的に探索)
‘ ———————————————————————
Private Function SearchShapeRecursive(ByVal shapesCol As Shapes, ByVal keyword As String) As Shape
Dim sh As Shape
Dim foundSh As Shape
Set SearchShapeRecursive = Nothing
For Each sh In shapesCol
‘ テキストフレームの場合の中身チェック、またはシェイプ名チェック
If sh.Type = cdrTextShape Then
If InStr(1, sh.Text.Story.AllText, keyword, vbTextCompare) > 0 Then
Set SearchShapeRecursive = sh
Exit Function
End If
ElseIf InStr(1, sh.Name, keyword, vbTextCompare) > 0 Then
Set SearchShapeRecursive = sh
Exit Function
End If
‘ グループシェイプの場合は内部を再帰探索
If sh.Type = cdrGroupShape Then
Set foundSh = SearchShapeRecursive(sh.Shapes, keyword)
If Not foundSh Is Nothing Then
Set SearchShapeRecursive = foundSh
Exit Function
End If
End If
Next sh
End Function
—
3. チーフアーキテクトが解説するコードの急所
A. `Application.Optimization = True` の絶対性
CorelDRAW VBAにおいて、ループ処理の中でページを切り替えたりオブジェクトを操作したりすると、GUIの再描画(Redraw)が走り、処理速度が数百倍に落ちる。
`Optimization = True` を宣言することで、バックグラウンドでのDOM操作に特化させ、CPUリソースを限界まで引き出すことができる。エラー時も含めて必ず `False` に戻す例外処理構造 (`On Error GoTo`) が必須である点に注意せよ。
B. グループ化構造を突破する再帰関数 (`SearchShapeRecursive`)
通常の `For Each s In p.Shapes` では、グループ化された図形(`cdrGroupShape`)の内部に隠されたテキストやオブジェクトをヒットさせることができない。
プロフェッショナルな環境では、オブジェクトがネスト(階層化)されていることを前提に、上記コードのように再帰呼出し(Recursive Function)を用いてグループの最深部まで確実にリーチする構造が求められる。
C. ビューポートの制御力 (`ToFitShape`)
目的のページへ移動するだけでは不十分だ。オペレーターは「どこにあるのか」を探すために目を酷使する。
`targetPage.Active = True` でページコンテキストを切り替えた後、`ActiveWindow.ActiveView.ToFitShape targetShape` を実行することで、CorelDRAWのビューポートが該当オブジェクトを的確に捉えてズームアップする。この「痒い所に手が届く」UXの統合こそが、実務で使えるツールの条件である。
—
総括
VBAはレガシーな言語と揶揄されることもあるが、CorelDRAWの内部API(GMS)を直接叩く権限を持つ最強のインターフェースである。
オブジェクトのライフサイクルを制御し、メモリと描画のボトルネックを排除したコードは、C#やVB.NETによる外形連携プラグインと同等、あるいはそれ以上の速度を発揮する。
日々の定型作業や、膨大な校正プロセスにおいて、この「一瞬で目的のオブジェクトを狩り出す」仕組みを組み込むことで、ワークフローの生産性は劇的に飛躍するだろう。現場のプロフェッショナルたちよ、このコードをベースにさらなる高みへとシステムを昇華させてほしい。
