【问题标题】:AutoLISP - Change Layers AutomaticallyAutoLISP - 自动更改图层
【发布时间】:2020-07-29 00:56:15
【问题描述】:

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

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

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

守则的概念

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

提前谢谢你。

【问题讨论】:

    标签: lisp autocad autocad-plugin autolisp


    【解决方案1】:

    暂停输入

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-02-03
      • 1970-01-01
      • 2011-02-28
      • 2023-04-03
      • 1970-01-01
      • 1970-01-01
      • 2012-04-26
      • 1970-01-01
      相关资源
      最近更新 更多