Sponsored links

【AutoLISP エラー処理】 よく使うエラー処理パターンの自作関数

Sponsored links
AutoLISP
Sponsored links
Sponsored links

予備知識

頻出パターンは自作関数に

エラー処理がついた自作コマンドを行くとも作っていると、エラー処理に関する部分、いつも同じだなと気付くと思います。

*error*の中身を保存して、*error*の中身を変えて、使うシステム変数の値を保存する。最後に、*error*の中身を戻して、使ったシステム変数の値を戻す。など。

このコード、いっつも書いてるな。と思う部分があるならば、自作関数にしてしまうのが便利です。

今回は、以下のコマンドにエラー処理を入れていきます。

エラー処理が必要なコマンド例

(defun Test_Function (/ r)
  ;---Jagaimo画層を作る-------
  (if (not (tblsearch "LAYER" "Jagaimo" )) ;もしJagaimo画層がなければ
       (command-s "._LAYER" "N" "Jagaimo" "" );作る
   );if	
  
  ;---システム変数を変更する------
  (setvar "CLAYER" "Jagaimo");現在画層をJagaimoにする 
  (setvar "OSMODE" 0);オブジェクトスナップを0にする
  
;---円を10個作る--------
  (setq r 10)
   (repeat 10
     (command-s "._circle" "0,0,0" r "")
     (setq r (1+ r))
   );repeat
;---;エラーを --------------

  (getpoint "クリックで正常終了/ESCでキャンセルエラー処理")
  
(princ));Test_Function終わり

上記の自作関数Test_Functionの働きは、

  • 画層”Jagaimo”が無ければ作る。
  • 現在画層をJagaimoにする。
  • オブジェクトスナップをクリアーする。
  • 中心点0,0,0に、円を10個作る。
  • ユーザー入力で、クリックなら正常終了、ESCならエラー中断。

です。

エラー処理を入れない状態でこのコマンドを使用すると、

現在画層が変わる。
オブジェクトスナップがオフになる。
Undoで戻したいとき、円の作図を10回戻さなければいけない。

途中でキャンセルした場合、そこまでに作図された図形が残る。

といった問題が出てきます。
なのでこのコマンドには、

システム変数(現在画層、オブジェクトスナップ)を元に戻すエラー処理
一連の操作をセットして1回のUndoですべて戻るようにする
キャンセル時は一連の操作も元に戻すエラー処理

が必要です。

実際に実行してエラー処理が無いとどうなるのか試してみましょう。

Test_Function関数をコマンドで実行できるようにしたのがこちらです。

(defun c:test ()
  (Test_Function) ;Test_Functionを実行
(princ))

Test_Functionと、c:test 、両方読み込むと、コマンドtestで実行できるようになります。

最後に”クリックで正常終了/ESCでキャンセルエラー処理”とユーザープロンプトが出てきます。
クリックすれば正常終了するし、ESCならエラー中断します。


どちらを選択しても、エラー処理を入れてないので、現在画層もオブジェクトスナップも元に戻りません。Undoで戻すと10個の円一つ一つ戻していかなければいけません。

実行するたびに現在画層が変わったりオブジェクトスナップがオフになっては使いづらいですよね。
やっぱり取り消そうと戻すとき、何回もUndoしなければいけないのも面倒です。
途中でキャンセルした場合予期せぬ図形などが残るのはトラブルの元です。

それでは、これにエラー処理を付けていきます。

エラー処理用の自作関数の例

エラー処理の部分だけでなく、コマンドの最初と最後の部分も関数してしまいましょう。

コマンドの最初にするエラー処理

コマンドの最初に入れる、

  • *error*の中身を保存
  • *error*の中身を変更
  • 使うシステム変数の値を保存

を1つの自作関数”Jaga00START“にしました。

(defun Jaga00START ()
;-----------------------------------------
  (setq OldErr *error*) ;標準エラー処理を保存
  (setq *error* Jaga00ERR) ;エラー処理をJagaERRにする
;--------------------------------------- 
  (command-s "undo" "be") ;UNDO[元に戻す] [開始(BE)]
;--------------------------------------- 
  (setq OldCmdEcho (getvar "CMDECHO")) ;CMDECHOの値を保存
  (setvar "CMDECHO" 0) ;CMDECHOの値を0にする
  (setq OldDynMode (getvar "DYNMODE")) ;DYNMODEの値を保存
  (setvar "DYNMODE" 3) ;DYNMODEの値を3にする
;-----------------------------------------
 (setq OldOsmode (getvar "OSMODE"))	 ;OSMODEの値を保存
 (setq OldLayer (getvar "CLAYER")) ;CLAYERの値を保存
;-----------------------------------------
(princ "\nJaga00START\n") ;Jaga00STARTが実行されたか確認用
(princ));defun

コマンドの最後にするエラー処理

コマンドの最後にに入れる、

  • *error*の中身を戻す。
  • システム変数の値を戻す

を1つの関数”Jaga00END“にしました。


(defun Jaga00END ()
  (setvar "OSMODE" OldOsmode)	 ;OSMODEの値を戻す
  (setvar "CLAYER" OldLayer) ;CLAYERの値を戻す
;-----------------------------------------	
  (command-s "undo" "end") ;UNDO[元に戻す] [終了(E)]
;-----------------------------------------	
  (setvar "DYNMODE" OldDynMode);DYNMODEの値を保存
  (setvar "CMDECHO" OldCmdEcho);CMDECHOの値を戻す
 ;-----------------------------------------	 
   (setq *error* OldErr) ;エラー処理を戻す
(princ "\nJaga00END\n")
(princ));defun

エラー処理関数

そして、エラー中断時に実行される、エラー処理関数です。

コマンド最後にしたい処理と、エラー中断時にしたい処理はほとんど同じなので、Jaga00ENDをそのまま入れました。これも自作関数にするメリットで、コマンド最後とエラー処理、2回同じコードを書かずに済みます。

(defun Jaga00ERR (msg)	
  (Jaga00END);Jaga00ENDを実行
  (command-s "undo" "1");UNDO[元に戻す] 1 回
(princ (strcat"\n Jaga00ERR\n " msg));JagaErr:とエラーメッセージ表示
(princ));defun

Jaga00ENDに、UNDOで最初に戻してエラーメッセージを出すことを加えています

エラー処理を加えたコマンド関数

よく使うパターンを関数にすると、コマンド関数をシンプルにすることができます

(defun c:test-err ()
  (Jaga00START) ;Jaga00STARTを実行
  (Test_Function) ;Test_Functionを実行
  (Jaga00END) ;Jaga00ENDを実行
(princ))

エラーを加えたコマンドtest-errのプログラム、これだけです。

このコマンドtest-errと、下にエラー処理に関する関数すべてをまとめたので、どちらも読み込んで、試してみてください。

(defun Jaga00START ()
;-----------------------------------------
  (setq OldErr *error*) ;標準エラー処理を保存
  (setq *error* Jaga00ERR) ;エラー処理をJagaERRにする
;--------------------------------------- 
  (command-s "undo" "be") ;UNDO[元に戻す] [開始(BE)]
  ;--------------------------------------- 
  (setq OldCmdEcho (getvar "CMDECHO")) ;CMDECHOの値を保存
  (setvar "CMDECHO" 0) ;CMDECHOの値を0にする
  (setq OldDynMode (getvar "DYNMODE")) ;DYNMODEの値を保存
	(setvar "DYNMODE" 3) ;DYNMODEの値を3にする
;-----------------------------------------
(princ "\nJaga00START\n") ;Jaga00STARTが実行されたか確認用
(princ));defun

;********************************

(defun Jaga00END ()
  (setvar "OSMODE" OldOsmode)	 ;OSMODEの値を戻す
  (setvar "CLAYER" OldLayer) ;CLAYERの値を戻す
;-----------------------------------------	
  (command-s "undo" "end") ;UNDO[元に戻す] [終了(E)]
;-----------------------------------------	
  (setvar "DYNMODE" OldDynMode);DYNMODEの値を保存
  (setvar "CMDECHO" OldCmdEcho);CMDECHOの値を戻す
;-----------------------------------------	 
  (setq *error* OldErr) ;エラー処理を戻す
(princ "\nJaga00END\n")
(princ));defun

;********************************
(defun Jaga00ERR (msg)	
   (Jaga00END);Jaga00ENDを実行
   (command-s "undo" "1");UNDO[元に戻す] 1 回
(princ (strcat"\n Jaga00ERR\n " msg));JagaErr:とエラーメッセージ表示
(princ));defun

最後にユーザープロンプトが出てきたら、クリックすれば正常終了するし、ESCならエラー中断します。


今回は、現在画層もオブジェクトスナップも元に戻ります。
一度のUNDOですべての円が消えます。
エラー中断を選んだ場合はさらに、円もすべて消えてコマンド実行前の状態に戻ります。

いろんなエラー処理パターン

今回は、Undo[元に戻す]+システム変数のパターンを作りましたが、
Undo[元に戻す]だけのもの、システム変数だけのものなどよく使うパターンをいくつか用意しておくといいと思います。

システム変数は、使わないシステム変数でも
”コマンド実行時に値を保存して、変更することなく最後に同じ値を入れる”
ことには特に害はないので、いくつかよく使うシステム変数を入れておくと、同じエラー処理関数を多くのコマンドに使えます。

まとめ

  • エラー処理でよく使うパターンは関数にすると便利。
  • システム変数は使わなくても同じ値を入れ直しても害は無いので、いろんなシステム変数を入れると汎用性が高くなる。

関連記事

エラー処理の練習問題です。

Comments