工作中经常在 AutoCAD 中原位粘贴各种零碎图形,而且会用到许多个 AutoCAD(有时还开一个 CASS),在它们之间交换文件麻烦死了。我想 Windows 中有不少剪切板增强工具,如 ClipX Ditto 之类,都提供多个缓冲位置,可以同时存储不同的文本,按照需要粘贴。AutoCAD 为什么没个类似功能呢?最后我研究了一番 Lisp 做了个简单的多重剪切板工具。

原理很简单,是利用”写块”和”插入块”的功能。使用前需要先配置缓存路径,目前是 ”F:/temp/” ,可以改成你自己的。完后按 c1 就是将选中对象存到剪切板位置1,按 v1 将其粘贴回来。这个临时图形是存在硬盘的,所以能直接粘贴到另一个进程的 CAD 中。

因为刚接触 Lisp 很多知识不了解,用 cond 函数时被括号内求值顺序卡了半天,最后总算弄明白了……这段很2的注释就不删除了,不知还有没有人遇到类似的问题。

;传送当前选择的图形对象,用于在不同文档,不同版本CAD之间转移所选对象
;按 x1 c3 v2... 使用
; x1 = 所选图形剪贴到缓存位置1
; c3 = 所选图形复制到缓存位置3
; v2 = 从缓存位置2粘贴回来

;让函数名直接表示参数,使操作按键尽可能减少
;有更好的办法么? #unsolved
(defun c:x1 () ( setq sss ( ssget)) (blocktransport "x" "1" sss))
(defun c:x2 () ( setq sss ( ssget)) (blocktransport "x" "2" sss))
(defun c:x3 () ( setq sss ( ssget)) (blocktransport "x" "3" sss))
(defun c:x4 () ( setq sss ( ssget)) (blocktransport "x" "4" sss))
(defun c:x5 () ( setq sss ( ssget)) (blocktransport "x" "5" sss))

(defun c:c1 () ( setq sss ( ssget)) (blocktransport "c" "1" sss))
(defun c:c2 () ( setq sss ( ssget)) (blocktransport "c" "2" sss))
(defun c:c3 () ( setq sss ( ssget)) (blocktransport "c" "3" sss))
(defun c:c4 () ( setq sss ( ssget)) (blocktransport "c" "4" sss))
(defun c:c5 () ( setq sss ( ssget)) (blocktransport "c" "5" sss))

(defun c:v1 () ( setq sss nil )     (blocktransport "v" "1" sss))
(defun c:v2 () ( setq sss nil )     (blocktransport "v" "2" sss))
(defun c:v3 () ( setq sss nil )     (blocktransport "v" "3" sss))
(defun c:v4 () ( setq sss nil )     (blocktransport "v" "4" sss))
(defun c:v5 () ( setq sss nil )     (blocktransport "v" "5" sss))

(defun blocktransport ( method num sss / p n fn info )
(setvar "filedia" 0 )
(setvar "cmdecho" 0 )
(setvar "insunits" 0 )
(setq p "f:/_temp_/") ;在这里配置缓存路径,使用斜杠(而不是反斜杠)
(setq n "_slot_") ;缓存文件名称,起名应该尽量诡异
(setq fn (strcat p n num ".dwg"))
(setq info "") ;成功后输出信息
(setq fn_rnd (strcat p "back_" ( rtos (getvar "cdate") 2 8 ) ".dwg"))

;这个 condition 明显是"点对"啊,
;为什么 (cond ( (= method "x") (bla...) (bla...) (bla...) ) 是对的
;而 后面那一堆括起来 (cond ( (= method "x") ((bla...) (bla...) (bla...)) ) 是错的?
;发现 (cond ((= 1 1) (alert "22") )) 没问题
;发现 (cond ((= 1 1) (alert "22") (alert "33"))) 也没问题
;但括起来后面的那堆 (cond ((= 1 1) ((alert "22") (alert "33")))) 却会先弹窗 33 ,从右向左!
;这什么破玩意
;发现((bla1) (bla2) (bla3)) 都是从右向左的
;也不尽然 括起来后,下面那些 (alert "1") - (alert "4") 顺序是 2 3 4 1
;不括起来,下面那些 (alert "1") - (alert "4") 顺序是 1 2 3 4
;也就是说 括起来后,()中第一个被视为函数,所以先求实参了?
;先加个 list 就可以括起来了 (list () () () bla1 bla2 bla3 blabla)
(cond
((= method "x") ;剪切图形 to slot
(list ;使用 list 串联表
;(alert "1")
(cond ((findfile fn) (command "-wblock" fn "y" "" "0,0" sss "" ))
('t (command "-wblock" fn "" "0,0" sss "" ))
)
;(alert "2")
(command "oops" ) ( command "-wblock" fn_rnd "" "0,0" sss "") ;备份唯一名称的图块
(setq info (strcat "*cut* to slot" num " done !"))
;(alert "3")
;(alert "4")
)
)

((= method "c") ;复制图形 to slot
;不使用 list 串联表,依次计算零散的分支
(cond ((findfile fn) (command "-wblock" fn "y" "" "0,0" sss "" ))
('t (command "-wblock" fn "" "0,0" sss "" ))
)
(command "oops" ) ( command "-wblock" fn_rnd "" "0,0" sss "") ;备份唯一名称的图块
(command "oops" ) ;写块时会从原图清掉这些图形,需要还原回来

(setq info (strcat "*copy* to slot" num " done !"))
)

((= method "v") ;粘贴图形 from slot
(command "_insert" fn "0,0" "1" "1" "0")
(setq ss (entlast))
(command "_explode" ss) ;炸开图块
(command "-purge" "b" (strcat n num) "y" "y") ;清理掉这个块的定义
(setq info (strcat "*paste* slot" num " done !"))
)

)
(setvar "cmdecho" 1 )
(setvar "filedia" 1 )
(prompt info )
)


WarmGrid

Answerers: April and Probe