CorelDRAW VBAを掌握する極限の知見
実務で通用する堅牢なVBA設計:アクティブページ頂点数監査ツールの構築
業務自動化エンジニアの私から言わせてもらえば、CorelDRAW VBAの開発において最も恐ろしいのは、「画面上では綺麗に見えるが、内部に数万〜数百万の無駄なノード(頂点)を抱えた爆弾データ」の存在だ。これを知らずに大判プリンターへの出力や、他形式へのコンバート(PDF/EPS等)へ回すと、RIP処理がフリーズするか、最悪の場合はアプリーケーション自体が強制終了する。
今回は、プロの現場で即戦力となる「アクティブページ内の全パスオブジェクトの頂点数を完全走査し、監査レポートを出力するツール」の設計思想とプロダクションコードを伝授する。
単に動くだけのコードではなく、「なぜそのオブジェクトをどう辿るべきか」「メモリとパフォーマンスの最適化」を意識した、実務直結のアーキテクチャを解説しよう。
—
1. なぜ「素朴なループ」では実務で破綻するのか?
初心者がやりがちなミスは、`ActivePage.Shapes` を単純な `For Each` で回し、ヒットしたシェイプのノード数を数えるという実装だ。
これでは、以下の実務的トラップに必ず足を取られる。
1. グループ化・コンテナのネスト問題
シェイプがグループ化されている場合、親グループを叩いただけでは内部のパスに到達できない。再帰的に階層を潜るロジックが必須となる。
2. 非パスオブジェクトの存在
ビットマップ、テキスト、ガイドラインなどは `.Curve` プロパティを持たないか、そのままではノードを持たない。エラーハンドリングなしに触ると `Run-time error 438 (Object doesn’t support this property or method)` が発生して即座に沈没する。
3. UIの再描画による圧倒的なパフォーマンス低下
マクロ実行中に画面の再描画(ScreenUpdating)を抑制しないと、数千のオブジェクトを走査するだけでウィンドウが激しく点滅し、処理速度が何倍にも跳ね上がる。
これらを完全にクリアした「プロのコード」を以下に提示する。
—
2. 【プロダクションコード】ノード数監査ツール
以下のコードをCorelDRAWのVBAエディタ(Alt + F11)の標準モジュールに貼り付けて実行してほしい。
Option Explicit
‘ ==============================================================================
‘ 著作権・ライセンス: MIT License
‘ 目的: アクティブページの全パスオブジェクト(グループ内含む)のノード数を走査し、
‘ イミディエイトウィンドウに監査レポートを出力する。
‘ ==============================================================================
Sub AuditActivePageNodes()
Dim startTime As Double
startTime = Timer
‘ 【重要】パフォーマンス最適化の鉄則:画面描画とイベントを停止
ActiveDocument.BeginCommandGroup “Node Audit”
CorelDRAW.Application.Optimization = True
On Error GoTo ErrorHandler
Debug.Print “==================================================”
Debug.Print ” CorelDRAW パス頂点数 監査レポート”
Debug.Print ” 対象ページ: ” & ActivePage.Index
Debug.Print “==================================================”
Dim totalShapes As Long
Dim totalNodes As Long
totalShapes = 0
totalNodes = 0
‘ アクティブページのトップレベルシェイプを走査開始
Dim sh As Shape
For Each sh In ActivePage.Shapes
Call ProcessShape(sh, 0, totalShapes, totalNodes)
Next sh
Debug.Print “————————————————–”
Debug.Print ” 監査完了”
Debug.Print ” 走査したパス数 : ” & totalShapes & ” シェイプ”
Debug.Print ” 総合ノード数 : ” & Format(totalNodes, “#,
0″) & ” 頂点”
Debug.Print ” 処理時間 : ” & Format(Timer – startTime, “0.00”) & ” 秒”
Debug.Print “==================================================”
CleanUp:
‘ 【重要】最適化フラグの確実な復元(これを忘れるとCorelDRAWが不安定になります)
CorelDRAW.Application.Optimization = False
ActiveDocument.EndCommandGroup
Exit Sub
ErrorHandler:
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “監査ツール エラー”
Resume CleanUp
End Sub
‘ ==============================================================================
‘ 再帰的シェイプ走査プロシージャ(グループやブレンドの内部まで潜る)
‘ ==============================================================================
Private Sub ProcessShape(sh As Shape, ByVal depth As Long, ByRef shapeCount As Long, ByRef nodeCount As Long)
‘ 1. グループ(LayerやPowerClip、OLEオブジェクト含む)の場合は再帰処理
If sh.Type = cdrGroupShape Then
Dim subSh As Shape
For Each subSh in sh.Shapes
Call ProcessShape(subSh, depth + 1, shapeCount, nodeCount)
Next subSh
Exit Sub
End If
‘ 2. パスデータ(Curve)を持っているか判定
‘ ※テキストや矩形、楕円であっても .HasCurve が True ならカーブに変換可能、
‘ または直接 .Curve オブジェクトを取得できる場合がある。
If sh.Type = cdrCurveShape Or sh.HasCurve Then
Dim crv As Curve
Set crv = sh.Curve
If Not crv Is Nothing Then
Dim nodesInShape As Long
nodesInShape = CountCurveNodes(crv)
shapeCount = shapeCount + 1
nodeCount = nodeCount + nodesInShape
‘ 詳細をイミディエイトに出力(インデント付き)
Dim indent As String
indent = String(depth 2, ” “)
Debug.Print indent & “[パス] ID: ” & sh.StaticID & ” | タイプ: ” & GetShapeTypeName(sh) & ” | ノード数: ” & nodesInShape
End If
End If
End Sub
‘ ==============================================================================
‘ カーブオブジェクトから正確なノード数を算出するヘルパー
‘ ==============================================================================
Private Function CountCurveNodes(crv As Curve) As Long
Dim subpath As SubPath
Dim total As Long
total = 0
‘ 1つのシェイプが複数のサブパス(穴あきパスなど)を持つことがあるため二重ループ
For Each subpath In crv.SubPaths
total = total + subpath.Nodes.Count
Next subpath
CountCurveNodes = total
End Function
‘ ==============================================================================
‘ シェイプのタイプ名を文字列で返すユーティリティ
‘ ==============================================================================
Private Function GetShapeTypeName(sh As Shape) As String
Select Case sh.Type
Case cdrCurveShape: GetShapeTypeName = “Curve”
Case cdrRectangleShape: GetShapeTypeName = “Rectangle”
Case cdrEllipseShape: GetShapeTypeName = “Ellipse”
Case Else: GetShapeTypeName = “Other Path”
End Select
End Function
—
3. コードのアーキテクチャと現場の知見
このコードが「プロダクション品質」である理由を、3つの観点からロジカルに解説する。
① `Optimization = True` による爆速化
CorelDRAW VBAにおいて、オブジェクトを大量に走査・操作する際、画面の再描画(UIの更新)は最大のボトルネックになる。`Application.Optimization = True` を宣言することで、裏側のグラフィックエンジンへの負荷を遮断し、純粋なメモリ上の演算に集中させることができる。
ただし、エラー時も含めて必ず `False` に戻す(CleanUpラベルの徹底)ことが、アプリケーションをクラッシュさせないための絶対的な鉄則だ。
② 再帰処理(Recursion)による完全な網羅性
実務のデータは、グループ化が何重にもネストしていることが日常茶飯事だ。`cdrGroupShape` にヒットした瞬間、自分自身のプロシージャを再度呼び出す(インデント深度をプラスする)設計にすることで、どれほど深く入り組んだデータ構造であっても漏れなくキャッチできる。
③ サブパス(SubPath)の概念への対応
CorelDRAWの `Curve` オブジェクトは、独立した複数のパス(パスファインダーで結合された穴あき図形など)を `SubPaths` コレクションとして保持している。単に `sh.Curve.Nodes.Count` と書くと、最初のサブパスしかカウントされない、あるいはエラーになるケースがある。すべてのサブパスのノード数を正確に合算するロジック(`CountCurveNodes` 関数)が実務では不可欠だ。
—
4. さらなる実務展開:データベース・外部連携への布石
今回は結果を「イミディエイトウィンドウ」に出力して終わるシンプルな構成にしたが、実際の現場ではここから発展させるべきだ。
- CSV / Excel出力への拡張
`Debug.Print` の部分を、`FileSystemObject` を使ったCSVファイルの書き込み、あるいは `CreateObject(“Excel.Application”)` を使った自動レポート生成へと置き換える。これにより、クライアントごとの「データ品質証明書」を自動発行するシステムへと昇華できる。
- 閾値オーバー時の自動アラート・警告シェイプの着色
もしノード数が「1,000」を超えているパスがあれば、自動的にそのシェイプの輪郭線を赤色(RGB: 255, 0, 0)に変更し、オペレーターに視覚的な警告を与えるギミックを組み込むことも容易だ。
総括
VBAは単なる「手作業の代替ツール」ではない。CorelDRAWの内部仕様(オブジェクトモデル)を正しく理解し、堅牢なエラーハンドリングとパフォーマンス制御を行えば、企業の生産性を劇的に引き上げる強力な武器となる。
今回のコードをベースに、あなたの現場のワークフローに合わせたカスタム監査ツールをぜひ構築してほしい。限界を超えた自動化の世界へようこそ。
