kokjoo89 发表于 2022-7-5 19:46:25

Lisp-向se提示用户输入

我想编写一些类似于autocad提示选项的lisp例程,例如“offset”命令,当命令提示输入偏移距离时,它还可以接收其他类型的输入“through/erase/layer”。或者当提示选择实体时,仍然可以接收“退出/撤消”关键字。
 
如何编写类似的lisp程序?
 
提前感谢。

Lee Mac 发表于 2022-7-5 19:58:22

研究initget函数。
 
举个简单的例子:
(initget "Through Erase Layer")
(setq ans (getdist "\nSpecify offset distance : "))

kokjoo89 发表于 2022-7-5 20:06:44

谢谢你,李先生。你真是太棒了。
我从你的教程中学到了很多。我会继续向你学习。

kokjoo89 发表于 2022-7-5 20:24:19

(setq ent_lst nil ent0 nil)
(while (= ent0 nil)
(initget "Distance")
(setq ans (entsel "\nSelect rectangle to chamfer : "))
(if (= ans "Distance")
        (progn
        (setq cdis (getreal "Chamfer Distance: <1.0>"))
        )
        (progn
        (setq ent0 ans)
        (setq ent_lst (entget(car ent0)))
        )
)
)
(if (= cdis nil) (setq cdis 1.0))
这是我所做的代码的一部分,用于提示选择图元(矩形)并选择更改倒角距离的选项。
倒角距离的默认值为1.0,如果我希望该值在默认情况下显示为1.0,但如果用户之前已经输入了一个新值,则会显示该值。
这可能吗?

Lee Mac 发表于 2022-7-5 20:26:48

 
你太善良了kokjoo89-我很高兴你能从我的教程中学习
 
 
您的代码是一个良好的开端-做得好
 
就我个人而言,我更喜欢使用以下结构:
(defun c:test ( / ans dis ent enx ) ;; Define function & declare local variables ('dis-global' remains a global variable)
   ;; Initialise global variable if null
   (if (null dis-global)
       (setq dis-global 1.0)
   )
   (while ;; While the following expression returns a non-nil value
       (progn ;; Evaluate the following expressions and return the result of the last evaluated expression
         (setvar 'errno 0) ;; Reset the ERRNO system variable (this sys var does not automatically reset)
         (initget "Distance") ;; Initialise the keyword for the next user prompt
         (setq ans (entsel "\nSelect rectangle to chamfer : ")) ;; Prompt the user for a selection or keyword
         (cond
               (   (= 7 (getvar 'errno)) ;; Missed pick
                   (princ "\nMissed, try again.") ;; Notify user & stay in loop
               )
               (   (null ans) ;; User pressed Enter
                   nil ;; Exit loop
               )
               (   (= "Distance" ans) ;; User entered keyword
                   (if (setq dis (getdist (strcat "\nChamfer distance <" (rtos dis-global) ">: "))) ;; Prompt user for chamfer distance
                     (setq dis-global dis) ;; Update global variable if user enters a new value
                     (setq dis dis-global) ;; Else use global variable value
                   ) ;; end if
               ) ;; end condition
         ) ;; end cond
       ) ;; end progn
   ) ;; end while
   (if ans ;; If an object was selected
       (progn ;; Evaluate the following expressions and return the result of the last evaluated expression
         (setq ent (car ans) ;; Obtain the selected entity name
               enx (entget ent) ;; Obtain the DXF data for the selected entity
         ) ;; end setq
         (princ ;; Print the entity type & chamfer distance for the selected object (just as an example)
               (strcat ;; Concatenate the following strings
                   "\nUser selected a " (cdr (assoc 0 enx))
                   " with a chamfer distance of " (rtos dis)
               ) ;; end strcat
         ) ;; end princ
       ) ;; end progn
       (princ "\nUser did not select an object.") ;; Else the user did not select anything
   ) ;; end if
   (princ) ;; Suppress the return of the last evaluated expression
) ;; end defun
(请注意,以上内容未经测试!)
 
在我看来,通过使用(while(progn))结构,可以更容易地控制循环,并避免需要“标志”变量。
 
这还允许错过选择,并允许用户在提示下按ENTER键退出。

kokjoo89 发表于 2022-7-5 20:42:36

:notworthy:再次感谢您的精彩代码,比我一整天所做的要好100倍。我会研究你的代码来改进我的lisp。
下面是我花了一整天的时间错误地尝试得到的冗长、杂乱、低效的lisp程序。这并不漂亮,但能完成任务。
 
该程序主要提示用户选择一个矩形,然后将矩形偏移到内部,对选定矩形的所有角进行倒角。然后创建4条线,将拐角连接到倒角。偏移和倒角距离相同,可以更改“距离”。
(defun C:PLA ()

(setq osmd (getvar "osmode"))
(setq ocmd (getvar "cmdecho"))
(graphscr)
(setvar "osmode" 0)
(setvar "cmdecho" 0)
(setvar "plinetype" 2)
(command "UCS" "world");reset UCS to "World"

(setq ent_lst nil ent0 nil)
(while (= ent0 nil)
        (initget "Distance")
        (setq ans (entsel "\nSelect rectangle to chamfer : "))
        (if (= ans "Distance")
                (progn
                (setq cdis (getreal "Chamfer Distance: <1.0>"))
                )
                (progn
                (setq ent0 ans)
                (setq ent_lst (entget(car ent0)))
                )
        )
)
(if (= cdis nil) (setq cdis 1.0))

(setq olyr (getvar "clayer"))
(setvar "clayer" (cdr(assoc '8 ent_lst)))

(if (= (cdr(assoc 0 ent_lst)) "LWPOLYLINE")
(progn

(setq len (length ent_lst))
(setq n 0)
(setq vernum 1 verlst nil)

(repeat len
        (setq ent_tmp (car(nth n ent_lst)))
        (if (= ent_tmp 10)
                (progn
                (terpri)
                ;(princ (cdr(nth n ent_lst)))
                (setq verlst (cons (cons vernum (cdr(nth n ent_lst))) verlst))
                (setq vernum (1+ vernum))
                )
        )
        (setq n (1+ n))
)

(if (= (length verlst) 4)
        (progn
        (setvar "chamfera" cdis)
        (setvar "chamferb" cdis)
        (setq midp_x (/(+ (cadr(assoc '1 verlst)) (cadr(assoc '3 verlst))) 2))
        (setq midp_y (/(+ (caddr(assoc '1 verlst)) (caddr(assoc '3 verlst))) 2))
        (setq midp (list midp_x midp_y))

        (command "offset" cdis ent0 midp "")

        (command "chamfer" "p" ent0)
       
        (if (< (cadr(assoc '1 verlst)) (cadr(assoc '3 verlst)))
                (setq pt_x (cadr(assoc '1 verlst)))
                (setq pt_x (cadr(assoc '3 verlst)))
        );get ori point_x to start line
        (if (< (caddr(assoc '1 verlst)) (caddr(assoc '3 verlst)))
                (setq pt_y (caddr(assoc '1 verlst)))
                (setq pt_y (caddr(assoc '3 verlst)))
        );get ori point_y to start line
        (setq pt0 (list (+ pt_x cdis) (+ pt_y cdis)))
        (setq ldis (/(sqrt (* (* cdis cdis) 2)) 2))
        (setq pt1 (polar pt0 (* 1.25 PI ) ldis))

        (command "line" pt1 pt0 "")
       
        (setq mid_ymp (list midp_x (1+ midp_y)))
        (setq mid_xmp (list (1+ midp_x) midp_y))
        (setq ent_l (entlast))
        (command "mirror" ent_l "" midp mid_ymp "N")
        (setq ent_2 (entlast))
        (command "mirror" ent_l ent_2 "" midp mid_xmp "N")
        (princ "\nDone")
       
        (command "UCS" "P");restore previous UCS
       
        )
        (progn
        (terpri)
        (princ "Invalid Rectangle, ")
        (princ "It has ")
        (princ (length verlst))
        (princ " corners")
        )
)
)
(princ "Invalid lwpolyline")
)

(setvar "osmode" osmd)
(setvar "cmdecho" ocmd)
(setvar "clayer" olyr)
(princ)
)
 
此程序的目标示例:
http://i.imgur.com/tsHEf1A.png
 
我在声明局部变量时仍然有问题。当我声明一些为局部变量时,程序不工作。非常混乱。关于lisp有很多需要学习的地方。
 
一些问题:
1) 我不熟悉(while(progn))结构,我只知道(while)。(while(progn))结构如何工作?它可以在没有旗帜的情况下工作?
2) (null xxx),(=xxx nil),(=xxx“”)之间有什么区别?
3) 为什么(如果是…)如果“ans”不是“T”/零,可以评估“ans”?它是否需要一些求值表达式,如(if(=ans xxx))?
 
再次感谢李:不值得:

Lee Mac 发表于 2022-7-5 20:56:13

 
就局部变量声明而言,以下内容可能有助于您更好地理解该概念:
 
局部变量范围
本地化变量
 
现在,回答您的问题:
progn表达式是本例中的测试表达式(或您所指的“标志”);然而,在我的示例中,在验证测试表达式时,没有要计算的表达式。
 
progn函数将仅计算提供的表达式,并返回最后计算的表达式返回的值。因此,使用此结构,我们可以计算许多表达式,并通过简单地控制最后一个计算表达式返回的值来控制循环-这在本质上类似于其他语言中的do-while表达式。
 
 
[列表]
[*]null验证符号或表达式的计算结果是否为零
[/列表]
 
[列表]
[*]=通常用于比较数字、符号或字符串的绝对相等性;因此,在本例中,您正在测试由符号xxx持有的值是否与返回true的符号nil相同。虽然在本例中,null和(=nil)的作用相同,但在语义上,我在本例中使用null。
[/列表]
 
[列表]
[*](=xxx“”)与(=xxx nil)完全不同:一个表达式正在测试符号xxx持有的值是否等于符号nil;另一个是测试该值是否等于空字符串。请注意,空字符串和nil非常不同:
[/列表]
_$ (= "" nil)
nil
_$ (< nil "")
T
在AutoLISP中,任何非nil表达式都可以验证条件函数的测试表达式(if/cond/while)。也就是说,如果符号或表达式不等于零,则将验证测试表达式-符号或表达式不需要包含布尔值。
 
观察:
_$ (if 1 "yes" "no")
"yes"
_$ (if "a" "yes" "no")
"yes"
_$ (if "" "yes" "no")
"yes"
_$ x
nil
_$ (if x "yes" "no")
"no"
_$ (if 'x "yes" "no")
"yes"
 
不客气!
页: [1]
查看完整版本: Lisp-向se提示用户输入