「動けばいい」というコードが、いかに現場の生産性を破壊するかを知っているか?
諸君、私は世界中のオートメーション現場で、数えきれないほどの「動かなくなったマクロ」を葬ってきた。初心者が陥る最大の罠は、「自分の環境では動いた」という慢心だ。特にAutoCAD VBAにおいて、画層(Layer)の操作はその筆頭と言える。
今回のテーマは「指定した画層がない場合に自動作成する」という極めて基礎的な処理だ。しかし、ここにはプロフェッショナルとアマチュアを分かつ決定的な「設計思想」の差が現れる。
ただエラーを回避するのではない。「堅牢で、速く、美しい」。そんなコードの書き方を伝授しよう。
—
1. アンチパターン:なぜあなたのコードは「脆い」のか
まず、初心者が書きがちな最悪のコードを見てみよう。
‘ 【アンチパターン】初心者が書きがちな「お祈り」コード
Sub BadExample()
‘ 画層を切り替えて作図したい
ThisDrawing.ActiveLayer = ThisDrawing.Layers(“MyLayer”) ‘ ← ここで爆発する
‘ 作図処理…
End Sub
このコードは、図面に「MyLayer」が存在しない瞬間に、実行時エラーを吐いて停止する。
「事前に手動で作っておけばいい」? 甘い。ツールを使うのは人間だ。人間は必ずミスをする。テンプレートを間違える。画層名をタイポする。
プロの仕事とは、「どのような不確定要素が入り込んでも、目的を完遂させる」ことにある。
—
2. 解決策:存在確認と自動生成の「カプセル化」
優れたアーキテクトは、一つの目的(画層の取得)のために冗長なコードをメインロジックに書かない。専用の「ファクトリ関数」を作るのが鉄則だ。
以下のコードは、指定した画層の存在を確認し、なければ作成、あればそれを返す。さらに、色や線種まで一貫して管理する。
プロフェッショナルな実装例:`EnsureLayer` 関数
”’
”’ 存在しない場合は、指定のパラメータで新規作成する。
”’
Public Function EnsureLayer(ByVal layerName As String, _
Optional ByVal colorIndex As Long = 7, _
Optional ByVal lineType As String = “Continuous”) As AcadLayer
Dim objLayer As AcadLayer
On Error Resume Next
‘ 1. Layersコレクションから直接取得を試みる(これが最速)
Set objLayer = ThisDrawing.Layers.Item(layerName)
On Error GoTo 0
‘ 2. 存在しなかった場合の処理
If objLayer Is Nothing Then
‘ 画層の新規作成
Set objLayer = ThisDrawing.Layers.Add(layerName)
‘ プロパティの設定(エラー防止のため線種設定は慎重に行う)
With objLayer
.color = colorIndex
‘ 線種がロードされていないリスクを考慮するなら本来はロード処理が必要
‘ ここでは簡略化のため、標準的なContinuous以外はエラーハンドリングを推奨
On Error Resume Next
.Linetype = lineType
On Error GoTo 0
End With
Debug.Print “Layer Created: ” & layerName
End If
Set EnsureLayer = objLayer
End Function
—
3. なぜ「For Each」で回してはいけないのか
ここで、ある「真面目な」初心者はこう思うかもしれない。「`For Each` で全画層をループして、名前が一致するかチェックすればいいのでは?」と。
それは「計算量の無駄」だ。
AutoCADの図面には、数百、数千の画層が含まれることがある。その中を毎回ループで探すのは、辞書をAから順にめくって単語を探すようなものだ。
VBAのコレクション(`Layers`)は、内部的にハッシュテーブルに近い構造を持っている。`Item(“名前”)` で直接アクセスする方が、圧倒的に速い。
プロは、「失敗することを前提にアクセスし、エラーをトラップする」という手法を、パフォーマンス向上のために戦略的に選択する。
—
4. 実戦での運用:メインロジックを汚さない
作成した関数をどう使うか。メインロジックはこれほどまでにクリーンになる。
Sub DrawSmartLine()
Dim targetLayer As AcadLayer
‘ 1. 画層の存在を保証する(なければ赤色の画層を作る)
Set targetLayer = EnsureLayer(“設備_配管”, acRed)
‘ 2. 現在の画層を切り替える
ThisDrawing.ActiveLayer = targetLayer
‘ 3. 作図開始
Dim startPt(0 To 2) As Double: startPt(0) = 0: startPt(1) = 0: startPt(2) = 0
Dim endPt(0 To 2) As Double: endPt(0) = 100: endPt(1) = 100: endPt(2) = 0
ThisDrawing.ModelSpace.AddLine startPt, endPt
MsgBox “作図完了。画層「設備_配管」は確実に存在します。”, vbInformation
End Sub
—
5. データベースや外部ファイル連携を見据えた拡張
実務では、画層の色や線種を「コード内に直書き(ハードコーディング)」するのは避けるべきだ。
将来的に、「画層名はExcelの設定シートから読み込む」「会社の標準CAD仕様DBから取得する」といった要求が必ず来る。
その際、この `EnsureLayer` 関数が独立していれば、引数を増やすだけで対応できる。
アーキテクトの視点:注意点
1. 線種のロード問題: `Continuous` 以外の線種(HIDDENやCENTERなど)を指定する場合、その線種が図面にロードされていないと、`objLayer.Linetype = lineType` でエラーになる。実戦配備するなら、`ThisDrawing.Linetypes.Load` を事前に呼ぶロジックを組み込むのが一流だ。
2. ActiveLayerの副作用: `ActiveLayer` を変更すると、ユーザーが元々いた画層を忘れてしまう。親切なツールにするなら、マクロの開始時に `OriginalLayer = ThisDrawing.ActiveLayer` で保存し、終了時に戻してやるのが「作法」である。
—
結論:基礎こそが、巨大なシステムの礎となる
「画層があるかないかを確認する」
これだけの処理に、なぜここまでこだわるのか。それは、例外処理(エラーハンドリング)の積み重ねが、ツールの信頼性を決めるからだ。
ユーザーの手を止めない。マクロを途中で落とさない。
この執念こそが、単なる「コードが書ける人」と「業務を自動化できるプロフェッショナル」の境界線である。
君のコードに、魂は宿っているか?
今日から、`On Error Resume Next` を「ただの逃げ」ではなく「戦略的な武器」として使いこなし、無敵のオートメーションを構築してほしい。
