AutoLISP - 自动更改图层

AutoLISP - Change Layers Automatically

我想制作一个简单的 AutoLISP 例程,在图层 "0" 中画线,然后改回原始图层。

使用下面的代码,我可以画一条线,但它会留在当前图层中。如果我放出最后一行代码,我在图层"0"画线,但之后没有改变回到原来的图层。

(defun c:testfunction (/ OLD)
  (setq OLD (getvar 'clayer))
  (setvar 'clayer "0")
  (command "line")
  (setvar 'clayer OLD)
)

准则的概念

我首先将当前图层存储在 OLD 变量中,然后将图层更改为 "0"。在 LINE 命令之后我变回 OLD 层。

提前致谢。

暂停输入

由于 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 function, which returns the bitwise AND,例如:

(logand 1 3) => 1

(logand 1 2) => 0

将其与 CMDACTIVE 系统变量相结合,我们得到:

(logand 1 (getvar 'cmdactive))

如果命令处于活动状态,它将 return 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) expression to the end of the function definition to suppress the value returned by the last evaluated expression. As written, the current function will return the value returned by the setvar函数,将原图层的名称设为

    我们可以在定义的末尾使用 (princ) 代替 return 命令行的空符号,从而干净地退出程序:

    (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 命令时自动创建、设置和重置当前层: