| 
UID120404积分0精华贡献 威望 活跃度 D豆 在线时间 小时注册时间2004-4-2最后登录1970-1-1 
 | 
 
| 
在程序中实现图层的检查及新建
×
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册 
    
 有些编程者编程时没有考虑到用户环境的不同,经常所编制的程序能运行在自制的模板图形上,而不能在用户的图形中运行,这种情况也是我经常碰到的。
 最容易碰到的是图层。程序中,经常会使用特定的图层来放置程序所生成的对象,比如说你将图层设置为“3”层,写出的程序如下:
 
 (setq oldLayer ( getvar "clayer")) ;将当前图层保存起来,以便以后的恢复
 (setvar "clayer" "3")              ;将图层“3”转换为当前图层
 
 这时,如果用户当前图形中在存在“3”图层,程序就会出错并中断。为此,你首先应判断“3”图层是否存在,采用以下的聚光灯中判断图层的存在:
 
 (tblobjname "layer" "3")
 
 这时,如果图层“3”确实不存在时,则可用以下函数内容建立该名称的图层:
 
 (entmake (list
 '(0 . "LAYER")
 '(100 . "AcDbSymbolTableRecord")
 '(100 . "AcDbLayerTableRecord")
 '(6 . "CONTINUOUS")
 '(62 . 3)
 '(70 . 0)
 '(2. "3")
 )
 )
 
 这样就可以建立新图层,完整的程序如下:
 
 (setq old_lay (getvar "clayer"))
 (if (=(tblobjname "LAYER" "3") nil)
 (progn
 (entmake (list
 '(0 . "LAYER")
 '(100 . "AcDbSymbolTableRecord")
 '(100 . "AcDbLayerTableRecord")
 '(6 . "CONTINUOUS")
 '(62 . 3)
 '(70 . 0)
 (cons 2 "3")
 )
 )
 )
 )
 (setvar "clayer" "3")
 
 可能有人会说,使用command转换及新建图层不是更加简单吗?但我总认为其它函数能完成的动作,最好不要使用“command”函数,因为可能下一个版本中,command所引用的命令内容会有变化(如功能的加强),使用程序出错。就象R12、R13、R14版中的清理命令[Purge]就各不相同。
 <回到顶部>
 
 
 
 将一个大程序分成多个小程序以简化编写过程
 
 初学者常常会将所有的功能都编入到一个程序(或函数)中。这不仅会使程序冗长难读,也会给修改和重用带来麻烦。AutoLISP是一种函数式的语言,因此,将一个单独的功能编制成一个函数可以使程序简明易读。对于重复调用次数较多的程序,应编制一个通用函数并在初始化时加载到环境中,以便于调用。
 
 <回到顶部>
 
 将自己编制的程序或函数的调用放在菜单系统中
 
 不要让自己编制的程序只能够从命令行调用,要将它们安排在菜单中以方便用户的调用。
 
 <回到顶部>
 
 不要将自己编制的程序全都放入ACAD.LSP文件中
 
 一些程序只喜欢将自己编写的程序或函数放在ACAD.LSP文件中,因为该文件可以在AutoCAD启动时装载到环境中。这样做的确可以方便自己编制函数的调用。不过,如果ACAD.LSP文件太大,则调入每个绘图的时间将变长,因为内存减小了。
 
 事实上,ACAD.LSP是用来存放通用函数的,只有频率很高的函数才应放入到ACAD.LSP中。例如:用户库函数通常都放在ACAD.LSP中,或在ACAD.LSP中加载。
 
 <回到顶部>
 
 加载文件前应判别程序是否已被加载
 
 在调用用户自己定义的函数之前,应将与之相关的应用程序加载到AutoCAD环境中,否则AutoCAD会报告不存在该函数。当一个函数会被多次调用时,如果每次调用之前都加载一次文件,则会浪费很多时间,因为一个文件只需加载一闪即可。这时,判别一下某文件是否已经装入是非常必要的,这种用法在菜单文件的语句中很常见,例如:
 
 ...
 
 [技术要求](if(not jsyq)(load"jsyq"));(jsyq);
 
 ...
 
 这里我们假定jsyq是文件jsyq.lsp中的一个函数(不是一个变量),在调用函数(jsyq)之前,(if not...)语句首先判断一下该函数是否已经存在。如果不存在,就加载相关文件jsyq.lsp;否则说明步过加载语句。
 
 <回到顶部>
 
 为自己的应用程序建立一个单独的目录
 
 不要将自己的应用程序放在AutoCAD软件包所在的目录下,这样不仅会扰乱软件包中文件的排列,也不便于管理。通常开发者会建立一个单独的目录来旋转自己的应用程序。此建立目录的名字应尽量避免可能会因安装 AutoCAD或其它第三方软件包而产生的冲突。
 
 <回到顶部>
 
 尽量减小应用程序的文件数
 
 AutoLISP程序通常都很短小,因为一个功能一般只需几十条语句就可以完成,这也是AutoLISP语言的效率所在。不过,如果将每一个编制的功能都生成一个单独的文件,不仅会使程序的数量繁多,而且使用时也要一次次加载,十分不方便。因此,应尽量将相关甚至相关性不太强的文件合并为一。这样,您可以将多个文件合为一个,使用时只要装载一次而无需多次装载。如本站提供的图栏程序和流程程序就是这样,图栏程序将六个相关的功能组合在一起,而流程程序将四个相关的功能组合在一起。
 
 <回到顶部>
 
 用缩进方法使程序便于阅读
 
 和其它软件开发程序一样,AutoLISP程序也可以使用缩进的方法进行编写以便于阅读,缩进后程序的调用并不多占用内存。
 
 <回到顶部>
 
 为变量取名应便于理解但不要太长
 
 在为变量取名时,应力求简洁且含义清晰。例如:ABC、QQX会被认为是无意义的,它不便于理解和记忆变量cornerpoint1虽然很便于理解,但它太冗长,会多占用内存。另外,变量名p1或pt1要比point1更为合适。
 
 <回到顶部>
 
 修改系统变量时应注意对原有变量的保存以便恢复
 
 AutoCAD启动之后,会为每个系统变量都初始化一个缺省值。在应用程序运行时,可能需要暂时将某系统产生的值修改一下。不过应注意在修改之前应将其原始值加以保存,使用完毕后再将其恢复回原始值。
 
 例如:在进行对象捕捉时,我们希望它使用终点捕捉方式,这时只要将系统变量OSMODE的值设为1即可。不过,在修改OSMODE的值之前,应将其原始值保存起来:
 
 (setq oldosmode(getvar "osmode"))
 
 然后再进行修改:
 
 (setvar"osmode" 1)
 
 这样再进行对象捕捉时,将使用终点方式。当捕捉结束之后,应将其恢复为原始的值:
 
 (setvar"osmode" oldosmode)
 
 此处oldosmode是一个用以保存OSMODE原始值的中间变量。
 
 <回到顶部>
 
 第三方开发的ACAD.LSP的引用
 
 很多第三方软件开发商在开发AutoCAD时会改写ACAD.LSP文件甚至将其加密。如果用户要在此基础上再开发自己的程序,则需要建立自己的ACAD.LSP文件。
 
 首先,将原来的ACAD.LSP文件为ACADOLD.LSP,然后建立一个自己的ACAD.LSP文件并在最后将原先的ACAD.LSP文件装载:
 
 (load "acadold")
 
 这样,AutoCAD启动时会自己装载ACAD.LSP文件,同时也装入ACADOLD.LSP文件,但有一点请注意,如果原先的ACAD.LSP文件中带有(S::STARTUP)函数,则按上述方法装入之后,该函数不会被自动执行,这时,你还应该在装载原先的ACAD.LSP文件之后运行如下语句:
 
 (S::STARTUP)
 
 <回到顶部>
 
 抑制函数运行之后返回的nil显示
 
 在一个AutoLISP运行结束之后,它常会在命令行上返回一个nil,我们可以在函数的最后一个右括号之前加上一条(princ)语句抑制nil的出现。
 
 注意:如果函数是用来返回一个值,则不能使用上述的方法。
 
 <回到顶部>
 
 为用户选择提供缺省值
 
 在AutoLISP应用程序中,当需要用户输入时,应为用户提供一个缺省的值。用户想输入的值刚好就是缺省的值时,只需按回车键或空格键即可,这样可以给用户带来方便。
 
 通常,缺省值跟在输入提示串之后并用尖括号(<...>)括起来,下面的例子中将最后一次用户输入的字符串存放在一个变量defvar中,当提示用户输入时,它将前一次用户输入的字符串做为缺省的值。
 
 (defun c:testpgm(/a)
 
 (if (= defvar nil)(setq defvar ""))
 
 (pormpt "\n输入名称:<")(princ defvar)(princ ">:")
 
 (setq a (getstring))
 
 (if (= a "")(setq a defvar))
 
 (setq defvar a)
 
 )
 
 注意:上面这段程序中,变量defvar是做为全局变量使用的,它将存在于AutoCAD环境中,运行testpgm之后,用户可以通过!字符检查defvar的当前值。
 
 <回到顶部>
 
 为命令行的选项提供右键快捷菜单
 
 在AutoCAD2000中,命令行中的可选项可以使用鼠标的右键显示,提高了用户的操作速度,但这种方法必须按照一定的格式书写程序,一般,选项内容是用中括号[...]括起来,每个选项之间使用"/"分隔。例如:
 
 (initget "Single Horizonal Vertical")
 (setq sele(getkword "\n部装明细序号填写方式[水平多项(H)/垂直多项(V)/单一序号(S)]<单一序号>:"))
 
 这样,在程序运行到当前提示时,用户可点击鼠标右键弹出快捷菜单显示各选项的内容选取。
 
 <回到顶部>
 
 关于程序调试的一些建议
 
 一个程序在编制是没有一定的规定的,因此,程序的调试方法也没有一定的规律。机器是不会告诉你程序到底错在哪里,你只能从逻辑上一遍又一遍地检查一个程序,可不幸的是,在某些情况下它还是会出错。
 
 从这种角度出发,我们说编程是非常令人生厌的,也是极具有挑战性的。其中最大困难的就是调试这一步,调试方法是否合适将直接影响到程序编制的进度。
 
 下面我们将介绍一些调试的策略。
 
 1.不要和计算机较劲
 
 请记住,计算机是不知疲惫的,可你不行。如果感到累了,可以暂时放下工作去花园散散步或干脆去看场电影,等你精神转好了再重新投入工作中去。
 
 2.计算机是非常公正的
 
 计算机的眼睛是雪亮的,它绝不会让任何错误的数据蒙混过关。加外,计算机几乎不会犯错误,因此,请多找一找自身的原因吧!
 
 3.在计算机中,相是的激励应该得到相同的结果
 
 有时,你的程序可能会在相同的输入下得到不尽相同的结果,这时你要提醒自己:一定有什么条件被改变了,虽然它还未暴露出来。
 
 在调试程序时更要注意这一点,不要因之而影响你的判断力。
 
 4.两种常见的错误类型
 
 语法错误和逻辑错误是程序中两种常见的错误类型。语法错误是较容易发现的,因为其中存在错误的命令,例如:
 
 (setq a (ang1 p1 p2))
 
 此处函数(ang1)拼写错了,正确的名字是(angle),系统会提示发现空函数而终止。
 
 逻辑错误是不容易发现的,例如:
 
 (angle pnt1 pnt2)
 
 这条语句看上去似乎是正确的,但如果pnt2的值为空,程序同样运行不下去。
 
 5.通过“断点”检查与变量有关的错误
 
 如果希望在程序运行到某处时检查变量a的当前值,可在程序中的该处加入如下语句:
 
 (princ a )
 
 (setq bp(getstring))
 
 这样,到印出a的值之后,函数(getstring)可使程序暂停,就好象遇到了一个断点一样,观察完a的值之后,可按任意键使程序继续。
 
 6.变量作用哉的定义
 
 在刚开始编程时,应将函数中用到的变量定义成全局性的。在AutoLISP中,函数中的变量只要不在函数定义defun命令的函数名之后的()中用斜杠说明,该变量就是全局的,例如:
 
 (defun drawline()
 
 ...
 
 )
 
 假设(drawline)用到了两个点pnt1和pnt2,则这两个将成为全局性的.用户可在命令秆用!字符检查它们的值.
 
 一旦将程序调试完毕确认无错之后,便可将变量定义成局部的,例如:
 
 (defun drawline(/ pnt1 pnt2)
 
 ...
 
 )
 
 这样,函数运行过程中pnt1和pnt2有效,运行完毕之后它们将消失,这样可以节省出一点内存空间来。
 
 7.注意不要混淆度和弧度
 
 当使用到角度时,最常见的错误是混淆了度和弧度两种单位,请记住,AutoLISP函数使用弧度为单位,AutoCAD命令使用度为单位。
 
 8.对相关的系统变量进行检查
 
 程序运行得正常与否与系统变量也有着直接的关系。例如:将对象捕捉系统变量OSMODE设置为终点捕捉模式(1)或交战捕捉模式(32),同一个程序在运行效果上可能就会产生很大的差别。
 
 9.从屏幕上的细微变化观察程序运行
 
 在AutoLISP程序运行时,屏幕上常会产生一些微小的变化,如:若出现一个表示点的小叉丝然后又消失,这有可能是在执行insert或与插入点有关的命令。若屏幕上的对象变成虚线表示,这有可能是在执行(ssget)函数并选中了这些对象,总之,仔细观察屏幕上的细微变化将有助于了解程序运行的进程,这对于程序的调试是有益的。
 
 10.调试通则
 
 程序出错通常是由多个错误引发的,而许多错误会导致同一种现象,因此,在分析错误时,应将它们分享出来进行检查,不要企图一次性将所有的错误都改正过来。
 
 <回到顶部>
 
 使命令暂停以等待用户输入
 
 在AutoLISP函数(command)中,您可以加入pause项使命令在执行到该处时暂时停下来以等待用户输入,例如:
 
 (command "circle" pnt1 pause)
 
 该命令将pnt1指定为圆心之后暂停,等待用户输入圆的半径值。
 
 <回到顶部>
 
 AutoCAD原始命令的取消与恢复
 
 UNDEFINE和REDEFINE是AutoCAD的两条命令。UNDEFINE用来取消AutoCAD的原始命令。例如:如果你在命令行上键入INDEFINE  FILLET,AutoCAD会禁止FILLET命令的使用,这样你使可以使用自己定义的FILLET命令。如果你想再使用AutoCAD的FILLET命令,这时应使用.FILLET命令,当然,你也可以干脆使用REDEFINE来恢复原先的状态。
 
 <回到顶部>
 
 (findfile)——查找文件
 
 (findfile)函数用来在磁盘上查找指定的文件,若只给出了文件名,则它会在当前路径、DOS的PATH环境变量所指定的路径和ACAD环境变量所指定的路径中查找该文件(找到第一个便停止)。例如:若要查找TYL.INI文件,则使用:
 
 (findfile "tyl.ini)
 
 它将返回:
 
 "c:\\program files\\acad2000\\tyl.ini"
 
 <回到顶部>
 
 (getenv)——取系统的环境变量
 
 库函数允许用户在AutoCAD环境中取系统的环境变量。例如:
 
 (getenv "acad")
 
 它将返回:
 
 "C:\\program files\\acad2000\\support;C:\\program files\\acad2000\\fonts;C:\\program files\\acad2000\\express"
 
 除ACAD之外,AutoCAD还有两个系统环境变量,它们是ACADCFG和ACADDRV。其用法相同。
 
 <回到顶部>
 
 (setcfg)——设置应用程序配置
 
 从AutoCAD  R13版开始,AutoCAD为应用程序开发者和用户提供了在ACAD14.CFG(AutoCAD2000中为ACAD2000.cfg)文件中保存半永久性配置信息的方法。该文件可以用记事本打开,文件分成两个部分。应用程序开发者和用户可以控制的那一部分被称为[AppData]。
 
 在本站所提供的图栏程序中就采用了该命令设置图栏的默认设计单位在tyl.ini文件中的位置及其它设计单位的名称,词句如下:
 
 (setcfg "AppData/Tyl/Number" 1 )
 (setcfg "AppData/Tyl/Other" "明经通道")
 该语句在ACAD.CFG文件中生成如下语句:
 
 [AppData/Tyl]
 
 Number=1
 
 Other="明经通道"
 <回到顶部>
 
 (getcfg)——取应用程序配置
 
 (getcfg)是(setcfg)的对偶函数,它用于从ACAD14.CFG(AutoCAD2000中为ACAD2000.cfg)文件中取出应用程序配置,以前面一节的例子为样板,下面语句:
 
 (getcfg "appdata/tyl/other")
 
 可取出ACAD14.CFG(AutoCAD2000中为ACAD2000.cfg)文件中Appdata中的Other的值。
 
 <回到顶部>
 | 
 |