暂停输入
由于 AutoCAD LINE 命令可以向用户发出任意数量的提示(取决于他们希望绘制的行数),因此您需要在代码中包含一个循环以允许任意数量用户输入,在重置当前层之前。
您当前的代码将评估表达式(setvar 'clayer OLD)在用户提供第一行点之前,因为用户输入没有暂停。
对于从 AutoLISP 程序或工具栏宏调用的 AutoCAD 命令中的 pause for user input,请使用反斜杠 \。
但是,由于反斜杠在 AutoLISP 中是 escape character,因此您需要在其前面加上另一个反斜杠,以便将 literal 反斜杠输出到命令,例如\\。
除此之外:pause 符号的计算结果也是反斜杠,但由于此符号不受保护并且可能会被重新定义,所以我始终建议使用文字反斜杠。
所以我们可以使用:
(command "line" "\\")
但是,这只会在单个输入时暂停,并且 AutoCAD LINE 命令将接受任意数量的输入,因此我们需要一种方法来构建循环并确定用户何时完成命令。
为此,我们可以使用CMDACTIVE系统变量,它是一个位编码的系统变量,指示当前命令状态-1的位代码表示命令处于活动状态。
要测试是否设置了位代码1,我们可以使用AutoLISP logand 函数,它返回两个提供的整数的按位AND,例如:
(logand 1 3) => 1
(logand 1 2) => 0
将此与我们拥有的CMDACTIVE 系统变量结合起来:
(logand 1 (getvar 'cmdactive))
如果命令处于活动状态,则返回 1,否则返回 0。
因此我们循环的测试表达式可以是:
(= 1 (logand 1 (getvar 'cmdactive)))
现在只剩下自己构建循环了——为此,我们可以使用 AutoLISP while 函数:
(while (= 1 (logand 1 (getvar 'cmdactive)))
(command "\\")
)
当命令处于活动状态时,上述内容将继续暂停以等待用户输入。
把它们放在一起
把所有东西放在一起,我们有:
(defun c:testfunction ( / old )
(setq old (getvar 'clayer))
(setvar 'clayer "0")
(command "line")
(while (= 1 (logand 1 (getvar 'cmdactive)))
(command "\\")
)
(setvar 'clayer old)
)
但是,我们可以在此处进行一些其他改进...
其他增强功能
-
我们可以在函数定义的末尾添加一个(princ) 表达式来抑制最后一个计算表达式返回的值。正如所写,当前函数将返回由setvar 函数返回的值,这将是原始层的名称。
我们可以在定义的末尾使用(princ) 来代替返回一个空符号到命令行,从而干净地退出程序:
(defun c:testfunction ( / old )
(setq old (getvar 'clayer))
(setvar 'clayer "0")
(command "line")
(while (= 1 (logand 1 (getvar 'cmdactive)))
(command "\\")
)
(setvar 'clayer old)
(princ)
)
-
我们可以在 AutoCAD LINE 命令的调用前加上下划线,以说明 AutoCAD 的本地化版本(其中 LINE 命令可能被称为其他名称):
(command "_line")
使用下划线命令前缀确保我们调用的是非本地化英语LINE 命令。
-
我们可以在 AutoCAD LINE 命令的调用前加上句点,以说明 AutoCAD LINE 命令的可能重新定义版本:
(command "_.line")
由于可以重新定义 AutoCAD 命令,因此使用句点命令前缀可确保我们调用的是未重新定义的标准 LINE 命令。
-
如果用户按Esc退出程序,我们可以添加一个本地错误处理程序自动将当前层重置为原始层:
(defun c:testfunction ( / *error* old )
(defun *error* ( msg )
(if old (setvar 'clayer old))
(if (not (wcmatch (strcase msg t) "*break,*cancel*,*exit*"))
(princ (strcat "\nError: " msg))
)
(princ)
)
(setq old (getvar 'clayer))
(setvar 'clayer "0")
(command "_.line")
(while (= 1 (logand 1 (getvar 'cmdactive)))
(command "\\")
)
(setvar 'clayer old)
(princ)
)
有关本地错误处理程序如何运作的更多信息,您可能希望参考我在 Error Handling 上的 AutoLISP 教程。
我们还可以测试以确保层 0 在尝试将其设置为当前层之前没有被冻结,但这超出了这个初学者程序的范围。
扩展理念
通过上述方法,我们定义了自己的自定义函数来存储当前层,设置一个新的当前层,调用LINE命令,然后重置原来的当前层。
但这意味着用户必须记住调用我们自定义版本的LINE 命令,而不是标准的LINE 命令。
如果有一种方法可以在调用标准 AutoCAD 命令时自动设置和重置当前图层?嗯,通过使用 Visual LISP Reactors,有。
在我的开源Layer Director 应用程序中,我演示了如何使用命令反应器和 LISP 反应器在调用标准 AutoCAD 命令时自动创建、设置和重置当前层: