【入門編】【上級】AcadDocument.Databaseオブジェクト深掘り:Undo/Redoスタックを考慮したトランザクション的な処理の実装 – AutoCAD VBA解析バイブル

スポンサーリンク

こんにちは!AutoCAD VBAの世界へようこそ。
マクロの記録ボタンを押して、生成されたコードを眺める段階はもう卒業しましたね。「もっとスマートに、もっとプロっぽく自動化したい!」そう思っているあなたなら、今日のお話は間違いなく目からウロコが落ちる内容です。

ここをクリアすれば、あなたの作ったVBAツールは「おもちゃ」から「プロ仕様の業務システム」へと劇的に進化します。心してついてきてくださいね。

1. なぜ「大量処理」のVBAは厄介なのか?

例えば、図面の中に散らばる数千個の円を一気に赤色に変えたり、レイヤーを一括で整理するマクロを作ったとしましょう。

VBAのコードが実行されると、AutoCADの画面上でオブジェクトが猛烈なスピードで書き換わっていきます。処理が無事に終わったあと、あなたはふと気づくはずです。

「あ、やっぱり今の処理、ちょっと条件間違えてた……。元に戻そう!」

ここでCtrl + Z(アンドゥ)を押してみます。するとどうでしょう。
数千個のオブジェクトを処理したはずなのに、「たった1個分」しか戻らない! あるいは、バラバラと細かく何百回もCtrl + Zを連打しなければ元の状態に戻らない……。

現場のデザイナーや設計者がこんなツール使ったら、怒りでキーボードを投げ出したくなりますよね。私たちは「一発で全変更をチャラにできる(=トランザクション的な)」スマートな仕組みを作らなければなりません。

2. 主役登場:DatabaseオブジェクトとUndoマーク

ここで登場するのが、今回の主役である `AcadDocument.Database`、そしてそれをコントロールする `StartUndoMark``EndUndoMark` です。

AutoCADの内部には、図面データを司る「データベース(Database)」という強力な心臓部があります。VBAからオブジェクトをゴリゴリ触るとき、このデータベースに対して「ここからここまでを、ひとまとめの作業(トランザクション)として扱ってね」と命令することができます。

図解するなら、こんなイメージです。

[VBAマクロ実行開始]

├─► 【StartUndoMark】 (ここから「1つの作業」として束ねるよ!)
│ ├─ 1つ目の円を変更
│ ├─ 2つ目の円を変更
│ └─ 3,000個目の円を変更

└─► 【EndUndoMark】 (ここまで!お疲れ様!)
[VBAマクロ終了]

⇒ ユーザーが「元に戻す(Ctrl+Z)」を押すと、
この一網打尽の束(マーク間)が【一瞬で】元の状態にロールバック!

この「マーク」を意図的に挟むだけで、数千回の変更がユーザー視点では「たった1回のアンドゥ操作」で綺麗に消えるようになります。これがプロの技です。

3. 実装コード:一括処理とUndo制御の完全テンプレート

百聞は一見に如かず。実際に、図面上のすべての円(Circle)の色をまとめて変更し、それを1つのUndoグループとして囲む実用的なコードを見てみましょう。

ご自身のVBAエディタ(Alt + F11)を開き、標準モジュールに貼り付けてみてください。

Sub ChangeAllCirclesColorPro()
Dim acadDoc As AcadDocument
Set acadDoc = ThisDrawing.Application.ActiveDocument

Dim db As AcadDatabase
Set db = acadDoc.Database

Dim errNumber As Long
Dim errDescription As String

‘ 【重要】エラーハンドリングの準備
‘ 万が一、処理中にVBAがクラッシュしてもUndoマークが開きっぱなしにならないようにする
On Error GoTo ErrorHandler

‘ —————————————————————–
‘ 1. Undoマークの開始(ここからトランザクション開始)
‘ —————————————————————–
db.StartUndoMark

Dim ent As AcadEntity
Dim circleCount As Long
circleCount = 0

‘ 2. モデル空間の全エンティティを走査
For Each ent In acadDoc.ModelSpace
‘ オブジェクトが「円 (AcDbCircle)」であるか判定
If TypeOf ent Is AcadCircle Then
‘ 例として、色を「赤 (ACAD_RED)」に変更
ent.Color = acRed

‘ 更新をデータベースに反映
ent.Update

circleCount = circleCount + 1
End If
Next ent

‘ —————————————————————–

  • 3. Undoマークの終了(ここまでを1つのグループに確定)

‘ —————————————————————–
db.EndUndoMark

‘ 成功メッセージ
MsgBox “処理完了: ” & circleCount & ” 個の円の色を変更しました。” & vbCrLf & _
“Ctrl+Z で一括して元に戻せます。”, vbInformation, “スマート自動化”
Exit Sub

ErrorHandler:
‘ 【極限の知見】エラー時の安全弁(フォールバック)
‘ 処理途中でエラーが発生した場合、Undoマークが開いたままになり図面が破損するのを防ぐため、
‘ 強制的にUndoマークを閉じさせてからエラーをスローします。
errNumber = Err.Number
errDescription = Err.Description

On Error Resume Next
db.EndUndoMark ‘ 開いている可能性のあるマークを強制クローズ
On Error GoTo 0

MsgBox “エラーが発生しました: ” & errDescription, vbCritical, “致命的エラー”
End Sub

4. コードの深掘りと「知っておくべき罠」

上記のコードには、単なるリファレンスの引き写しではない、現場の修羅場をくぐり抜けてきたエンジニアの知見が詰まっています。いくつか重要なポイントを解説しますね。

① `StartUndoMark` と `EndUndoMark` は必ずペアにする

コードを見てもらうとわかる通り、`StartUndoMark` を呼んだら、正常終了時だけでなく、エラーが発生したとき(ErrorHandler内)でも必ず `EndUndoMark` を呼ぶ 構造にしています。
もしこれをサボってエラー落ちすると、AutoCADのUndoスタックが狂い、最悪の場合その図面ファイルが保存できなくなったり、次からの操作がデタラメになったりします。ここ、本当に要注意です!

② 画面描画のロック(パフォーマンスの極意)

今回はシンプルにするために省きましたが、数万個のオブジェクトを相手にする場合は、処理の冒頭で画面描画をフリーズさせると、実行速度が劇的に跳ね上がります。

‘ 処理の最初で描画をロック(画面のチラつきと無駄な再描画を防ぐ)
acadDoc.Utility.SetVariable “REGENMODE”, 0

処理が終わったら、最後に `REGENMODE` を `1` に戻し、最後に `acadDoc.Regen acAllViewports` を呼んであげれば完璧です。

まとめ

いかがでしょうか?
今回は `AcadDocument.Database` オブジェクトを掘り下げ、Undo/Redoスタックを制御するトランザクション的な処理の実装方法を解説しました。

  • 大量のオブジェクトを書き換えるときは、必ず `StartUndoMark` で囲む。
  • ユーザーが「Ctrl + Z」1回で元に戻せる親切設計を心がける。
  • エラー時も考慮して、`EndUndoMark` は絶対にやりっぱなしにしない。

ここをクリアできたあなたは、もう「ただのマクロ記録ユーザー」ではありません。立派なAutoCAD業務自動化エンジニアです。ぜひ現場のツール開発に応用してみてくださいね。それでは、次のステップでお会いしましょう!

タイトルとURLをコピーしました