明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 1411|回复: 9

[经验] AutoLisp 总结

  [复制链接]
发表于 2019-5-29 12:37 | 显示全部楼层 |阅读模式
本帖最后由 1291500406 于 2019-5-29 13:14 编辑

在本章中,我们将更多讨论有关在Visual LISP中使用ActiveX性能。首先,我们从ActiveX的技术环境开始,包括对象、对象模型、集合、属性、方法等方面。然后我们将深挖一些特定的ActiveX技术部分。了解ActiveX功能性是学习任何语言必不可少的工作。

ActiveX是一种面向对象的工具,也就是说它表现为对象的使用以及对象间的关联这种方式。在这里我不想去解释面向对象的问题,这些东西最好留给那些更专业的教科书去讲。然而,我将尝试给一些基本的面向对象方面的描述,以便大家有一个基本的了解。



在面向对象的环境中,任何事物都是以Classes(类)开始的。类是抽象的框架,用于描述对象应是什么样的,以及他们应该如何表现和相互联系的。在某种意义上说类定义了对象类型的种类。例如,一辆汽车是属于交通工具类。交通工具是父类,而汽车是子类。反之,你可取得更多特定的和额外定义的子类,例如旅行车、面包车和运动型轿车。

类不处理特定的实例,他们更注重于实例方面的描述,而非使用方面。当你使用类时,你可以说调用类的一个实例。调用类的结果经常是创建了一个对象。对象可以是单独的图元或包含了更多对象的容器。

对象
一个对象就是类的一个实例。对象有其固定的属性,同时也可以有固定的方法和事件。属性是定义对象怎样表现和反应的特性。方法是用于访问或修改对象属性或某些行为的内置函数。事件是由对象发送的通知,当执行或激活它们时,它用于响应特定动作。

就用上面的汽车类的例子来说,对象可以是特别的轿车。比如说,你的轿车,带有特别的配置(制造、型号、颜色、选配、以及序列号)。你可以说,你的轿车是汽车类的一个实例,或汽车类派生的一些类。

图3-1 对象模型

对象模型
对象模型是一个随意的架构,或类之间的分层定义的排列关系,意思就是可以从更高级别的类来获得一个对象。对象模型与访问它的语言或工具无关,它有自己的逻辑框架。不管你是使用Visual Basic、VBA、Visual LISP、Delphi、Java、C/C++、C#.NET或带有ActiveX接口的其它语言,它都将以相同的模型存在。这并不代表对象模型的所有特性都支持所有语言。某些特性在某些语言中可以访问或比较容易被访问,但在其它语言中可能就不行。

我们将对象模型比喻成一套房子,它由房间、门和窗组成。不同的人都可进入和使用房子,而他们都是面对同样的这套房子。在这种情况下,房子和房间就是对象模型,而人即是编程语言。这样,你应该懂吧。

类继承
对象模型通常都是从根或源对象开始。在AutoCAD中,源对象是AutoCAD Application (AutoCAD应用程序)对象,也被称之为AcadApplication对象。它提供了基本的属性、方法、事件和来自所有其它对象和集合构成的集合。例如,AcadApplication对象有一集合为Documents(即Documents集合),在其中对应有一个或多个Document对象。每一Document对象有它自己的对象、集合、属性和方法以及其它东西。

你可向下层浏览对象模型进入下一层次的对象和集合,也可以向上层浏览父对象和集合。模型非常强大,应用程序可直接访问和操作环境来执行几乎无限的任务。它同时保持每一事物都整齐有序,在开发软件解决方案时能提供有效的帮助。

集合和词典
集合是在相同父窗口中一组相似的对象。该容器有一个独特的名字,在大多数情况下,将提供自己的方法来访问所包含的对象。词典是一种特殊类型的集合,它允许你扩展你自己的词典。Visual LISP并没有过多提供用于创建或处理集合的方法。它允许你遍历它、修改项目、添加或删除条目。词典允许你添加自己的词典并写入数据,你可遍历它、添加、修改和删除其条目,同样,你也可以添加 、修改和删除词典本身。

在AutoCAD中的一些公共的集合有Documents(文档)、Layers(图层)、Dimension Styles(标注样式)、Linetypes(线型)、 Blocks(块)等等。

在AutoCAD中的一些公共的词典有PageSetups (页面设置)、Layouts (布局)(它同样也做为词典保存),还有Express Tools中的个别组件,如WipeOuts (遮罩)。Xrecord对象也保存在词典内。

属性、方法和事件
属性只是描述关联于对象或集合的特性。例如它可包含名称、高度、宽度、旋转角度、比例缩放、颜色、图层、线型等等。属性根据不同的对象的类型而有所区别,但有些属性对所有对象和集合是通用的。集合和词典通常提供了Count和Name属性,还有Item和Add方法。只有词典提供了Delete方法,而你却不能通过Visual LISP删除集合。

方法是对象提供的用于访问或编辑专用特性或针对对象本身执行特别动作的内置函数。常见的方法有Rotate(旋转)、Erase(删除)、Copy(复制)、Scale(比例缩放)和Offset(偏移)。你可能注意到,这些看起来就像AutoCAD编辑命令。嗯,在本质上是这样的,但略有不同。

然而一般的AutoCAD编辑命令,必须在每步执行中验证对象。而方法是由主对象提供的,因此,只能由每一对象单独提供支持的方法。晕了吧?

另一种方式,OFFSET(偏移)命令可以在任何时间使用,但如果你试图偏移一个文本对象, AutoCAD就会出现出错信息。然而,文本对象本身提供的各种方法,如Copy(复制)、Rotate(旋转)、Scale(比例缩放)和Move(移动),但没有Offset(偏移)。所以你可以从对象“调用”各种方法,却需要确定它对使用的对象是有效的。

事件是对象或集合由各种可以被检测到的或可以响应的活动所产生动作。当事件与这些事件的反应相结合使用时,就称为事件驱动编程。AutoCAD提供了一个被称之为反应器的强大的事件反应工具集,它使你可在绘图环境中发送触发器来响应各种事件。例如,当对象在活动的图形中被删除时,您可以创建一个反应器响应一个Erase事件。这只是一个事件和反应器的例子。

属性关联
有一点很重要,就是你决不需要知道哪些属性适用于哪些对象和集合。有两个特别的函数对于保证您的代码能够在运行时妥善处理属性和方法的执行:(vlax-property-available-p)和(vlax-method-applicable-p)。这两个函数只是两个Visual LISP判断函数,它提供布尔测试判断条件是真或假(LISP术语为non-nil或nil)。

这些函数的语法如下:
(vlax-property-available-p object property)
(vlax-method-applicable-p object method)

属性是跟与之关联的对象的类型相关。例如,一个Circle(圆)对象有一个Diameter(直径)属性,但Line (线)对象就没有。根据不同的对象类型,属性也各不一样,下面的代码在拾取CIRCLE(圆)图元时会出错:

(if (setq ent (entsel "\n选择对象以获取其属性: "))
  (progn
    (setq obj (vlax-ename->vla-object (car ent)))
    (princ
      (strcat "\n长度: " (vla-get-Length obj))
    )
  )
)

但是,如果在取对象的属性前先检验该属性是否有效时,代码的执行就能正常,如下面的例子所示:

(if (setq ent (entsel "\n选择对象以获取其属性: "))
  (progn
    (setq obj (vlax-ename->vla-object (car ent)))
    (if (vlax-property-available-p obj 'Length)
      (princ
        (strcat "\n长度: " (vla-get-Length obj))
      )
      (princ "\n对象没有 LENGTH 属性…")
    )
  )
)

不幸的是,没有直接的方法获取给定对象的所有属性的列表来用于遍历编程。不过,你还是可以获取列表信息的,这样对你的帮助也不算小。

要查询在给定的对象上有什么属性和方法,可在该对象上使用(vlax-dump-object)函数。函数的语法是(vlax-dump-object object show-methods), show-methods参数可以是nil或非nil。如果是非nil,就显示对象支持的方法,否则就不显示方法。

图 3-2 – Documents集合的属性和方法

图3-2显示了Documents集合对象的属性和方法。你可看到输出的第一行显示了带有一个描述的内部对象参照(IAcadDocuments),并且列出了可用的属性和方法。

提示! 以下的命令定义对显示所选图元的属性和方法会有用处。它没有提供出错处理,但是它仍是个有用的小工具。

(defun C:BB (/ ent obj)
  (while (setq ent (entsel "\n选择图元以获取对象数据: "))
    (setq obj (vlax-ename->vla-object (car ent)))
    (vlax-dump-object obj T)
    (vlax-release-object obj)
  )
  (princ)
)

提示! 属性后面的括号(RO)代表该属性为只读,在这里,所有的属性均为只读,方法后面括号内的数字表示了每一方法所需要的参数数目。

要访问属性,可使用(vla-get-xxx)函数,或更通用的(vlax-get-Property)函数,两者都可以。第一个函数的语法是(vla-get-xxx object),其中XXX是属性名。在使用(vlax-get-property)函数时,语法为(vlax-get-property object propertyname),其中propertyname可以是双引号字符串或单引号字符串。

(vlax-get-property object property) 或
(vla-get-property object) 或
(vlax-get object property)

返回值是分配给该对象的指定名称属性的值,如果该对象的指定属性不存在,就会产生错误。举例来说,如果你对Line(直线)图元查询“Diameter”(直径)属性,就会产生错误。

参数:
Object – 一个 vla-对象
Property – 与对象相关的有效属性。

示例:
(vlax-get-property objLine “Length”)
(vlax-get-property objLine ‘Length)
(vla-get-Length objLine)

所有这些语句都将完成同样的事情。

属性的名称并不要求区分大小写,但本书的例子都将首字母大写,以示清晰。总的来说,你会发现以上前两项都很好用,但也有情况是要求用到后两项。特别是涉及到象Microsoft  Excel 或 Word这样的外部应用程序。第四种方式 vlax-get 是R14版遗留下来的,只为了向后兼容而已。

使用方法
通过图3-2的例子,你可看到Documents集合对象支持4种方法:Add、Close、Item和Open。Item方法需要使用一个参数(也就是在图3-2中显示在方法后面的那个(1)),它是由集合所引出的文档的索引和命名。

通常Item方法有一个有趣的特性,那就是它可以接受字符串或整数值参数。当给的是整数参数时,它就简单地返回集合的第(nth)条目,0为第一条目。当给的是一个字符串值时,它尝试通过它的名称属性来取得条目。Item (名称)方法不分大小写,这是相当有用的,它不需要先对字符串进行大小写转换就可以接受名称。

提示! 如果你熟悉Visual Basic或VBA并经常使用默认方法和默认属性,那你要注意,这种特性在Visual LISP是不存在的。例如,在Visual Basic中,通过以下任意一种途径来访问Item方法都是可行的:
Object.Item(12) 或 Object(12) 或 Object(“Name”)

这是因为在VB或VBA中,Item方法是大多数对象的默认方法。Visual LISP并不支持这种特性,它需要在每次使用时都阐明所有属性和方法。例如:

(vlax-invoke-method documents “Item” 12) 会有效果…
(vla-item documents “Drawing1.dwg”) 会有效果…
(vlax-invoke-method documents 12) 不会有效果。

使用图3-2的例子,Item方法可通过以下任何方法使用:

(vla-Item documents 1)
(vla-Item documents “Drawing1.dwg”)
(vlax-invoke-method documents “Item” 1)
(vlax-invoke-method documents ‘Item “Drawing1.dwg”)

(vlax-invoke-method object method [arguments]...) 或
(vla-method object arguments) 或
(vlax-invoke object method [arguments] ...)

调用关联于对象的方法并为方法提供任何所需的参数。如果成功,将返回结果。如果对象没有提供对应的方法,将会产生ActiveX错误。例如,在Text(文本)图元中调用“Offset”(偏移)方法,将会产生ActiveX错误。

参数:
Object – 一个vla-对象
Method – 由对象显露的方法
Arguments – 支持该方法的任何所需的参数

示例:
(vlax-invoke-method objLine “Move” point1 point2)
(vla-Move objLine point1 point2)
(vlax-invoke objLine “Move” point1 point2)

所有这些示例做的事情都一样。对于大部分AutoCAD对象来说都是可行的,但对于由TypeLib接口或外部应用程序或ActiveX组件输入创建的对象则不都可行。你可以将第一种方法用于外部应用程序对象,而可以将第二种方法用于内部对象。第三种方法是为了R14的向后兼容。

提示! 当你选择对属性和方法用Get或Put中的任意一种形式时,你会发现用较长的形式(如vlax-put-property)比用较短的形式(如vla-put-color)更灵活。原因是通过从函数中分离出属性名称,你就可以定义函数和循环语句,它们可以接受一个属性列表及相关的数值,例如...

(defun MapPropertyList (object proplist)
  (foreach propset proplist
    (if (vlax-property-available-p object (car propset))
      (vlax-put-property object (car propset) (cadr propset))
    )
  )
)

当试图在方法上使用这种方式时要特别小心,因为方法的参数列表会随着对象和方法的变化而变化。有一些方法不需要参数,而另一些则随长度变化。
数据类型

数据类型是用于描述给定对象或属性可包含的数值的类型。数据类型的例子有整数、双精度、货币、日期、字符串等等。在AutoLISP已经享受“类型无关”多年后,Visual LISP也同样可以,但不单只这样。在AutoCAD里,你可以尽可能地通过AutoLISP来保留这种类型无关,但当涉及其它应用程序时,例如Microsoft Excel,你将不可避免而且明智地用到数据类型。

类型无关并非免费午餐,其代价是效率低下。当你提前声明了数据类型,你就通知编译器调动仅仅够用的资源来匹配预定数据。例如,存储整数类型的数据远比存储“长”数据值要低得多。当你未使用数据类型时,所有数据都会自动分配尽可能长的数据类型,以确保能匹配所有可能出现的数据。其结果导致应用程序消耗的资源远比它的需求大得多,无论是从初始加载的尺寸或者其运行时间资源的分配。

这就是为什么程序开发的语言中,象C++、Java,甚至是Visual Basic通常都是比较快的(相比使用自由类型语言编程的同样功能)。他们确保能提前精简处理以保证运行时有更快的性能。AutoLISP并不这样做,因此是相对慢的处理语言。而Visual LISP相对会快一些,但只有你利用其新的特性,让其最尽可能发挥。

常量和枚举
常量是特殊的数据类型。正如其名,它的值是不可改变的。有时被称为静态。通常来说,常量是由程序语言或由托管应用程序本身提供,作为一种方便的手段。例如,acByLayer常量在属性值中可以被256代替。名称值比整数值更好明白也更好记。例如,以下两个语句在功能上说是一致的。

(vla-put-color object acByLayer)
(vla-put-color object 256)

枚举是常量的逻辑组合,它用来确定常量值范围。例如你可以用颜色值1、2、3、4、5,但也可以将之常量化为acRed、acYellow、acGreen、acCyan、acBlue、acMagenta和acWhite,这样更清晰。这种类型的相关常量值范围即称为枚举。参看附录A为标准的AutoCAD枚举清单。

提示!并不是所有的ActiveX枚举都在Visual LISP中有提供。例如,标准的Decimal(十进制)或Short(短)数据类型并没有镜像为vlax-vbDecimal或vlax-vbShort。请参阅第六章学习更多关于数据类型的信息。

变体和安全数组
在上节的数据类型中,有提到对自由类型声明使用最大的可用配额,例如在AutoLISP中的(setq)语句。事实上,是分配了一个变体数据类型,变体包括所有的数据类型,它提供了足够的资源空间去包含任何其它数据类型,可以是数值、日期、字符串或其它。事实上,变体数据类型是ActiveX产生出来的。但这个概念更具有一般性,在ActiveX之前已经存在很长的时间。

事实上Visual LISP包含了将所有ActiveX数据转换为带有指示包含哪类类型的区分符的变体。感觉有点乱,但事实很简单。该容器是一个包含有货币数据类型值的变体,当你分配给对象一个新值时,你必须提供区分符以使得这个数据能够正确储存。这是必须要做的,尤其是你在AutoCAD和其它应用程序(如Microsoft Excel)之间传递数值时。

除了发送数值外,你还可以从变体值中查询嵌套的数据类型,也可将值正确的转换成为相关的LISP数据类型。例如,你可查询变体对象值是否包含了双精度值。然后你可以在LISP中将这个数值读取为实数(REAL)数据类型。Visual LISP提供了大量的函数用于在LISP环境中创建、读取、修改变体量数据值。

安全数组相当于AutoLISP中的LIST对象。主要的区别在于它是静态的。意思就是说他不可能根据他们能存储的数字的多少来加长或改变项数。这将避免了在试图分配或取得超出数组长度的元素时产生的不必要的错误。这就是它们之所以被称为“安全”的原因。任何传递到ActiveX的LIST结构必须先转换成安全数组。任何从ActiveX对象获得的LIST面向对象的数据都必须通过象(car)、(nth)、(accoc)、(mapcar)、(member)等的LISP函数转换成LIST数据类型。Visual LISP为创造操作、阅读安全数组数据值提供了大量的功能。

更多关于变体和安全数组的内容,请参阅第六章。

命名空间
命名空间是分配用于运行过程的虚拟空间,它与空间中的其它资源相互配合。但它有时也可以和其它命名空间中的其它过程相联系。可以把命名空间想象成卧室。你的应用程序就如在卧室工作的人,也即在特定命名空间的过程。其它的应用程序就如在邻近卧室(命名空间)工作的一样,这两个人可以相互独立和隔离的,但他们也可以互相传递数据以便沟通。这就是命名空间工作的原理。

使用命名空间的好处在于可以在特定的命名空间中的过程与另外命名空间相独立的,这样可以在它们之间不相互破坏(如在争夺保存资源时)。它们也可直接通过它们的命名空间加载和卸载过程。换句话说,这有点象拆掉房子里一间卧室,而房子就如模块化形式建的一样。移去一个房间不会影响到其它房间或过程的生存。

可能使用命名空间最大的短处是会导致在操作系统或其宿主应用程序上的一些开销。为了管理好给定的命名空间,它必须有自己的内存地址范围和指针分配。这需要消耗额外的资源去跟踪和控制命名空间,这反过来又在必要时提供了直接的方法去访问它、卸载它或暂停它。

AutoCAD提供了在Visual LISP内部对命名空间的内部管理方法,同样在ObjectARX和VBA中也可以。这是Visual LISP比AutoLISP功能强大改进的又一表现。实际上每个打开的文档都是其自己的命名空间(如果你不是在单文件模式下工作的话),当在一个图形中设置一个变量而又试图在另一个图形中读取它时,这个影响就会看到。是有办法可以实现在这些图形中传递变量的,我们第十章将会谈到。

接口和类型库
接口是用于连接其它ActiveX过程或构件的对象模型的手段。当你想利用其它应用程序的特定的属性、常量或方法时,你首先要定义一个接口去加载那个目标应用的对象模型。例如,有时你想通过Visual LISP来利用Excel自己的工具直接用Microsoft Excel来保存一些AutoCAD信息到电子表格文件。这就需要定义接口,然后就可使用类型库

要使用类型库,就必须将其加载到内存,并确定接口指针已经定义。Visual LISP提供了一毓函数用于加载和配置类型库接口。

(vlax-import-type-library
  :tlb-filename name string
  :methods-prefix    string
  :properties-prefix string
  :constants-prefix  string
)

输入类型库参照到当前命名空间中。

参数:
:tlb-filename string – (字符串) 为类型库文件的路径和文件名
:methods-prefix string – (字符串) 为任意前缀字符串标识符
:properties-prefix string – (字符串) 为任意前缀字符串标识符
:constants-prefix string – (字符串) 为任意前缀字符串标识符

示例:
(vlax-import-type-library
  :tlb-filename             "c:\\myfiles\\typelibs\\tlfile.tlb"
  :methods-prefix           "dsxm-"
  :properties-prefix        "dsxp-"
  :constants-prefix         "dsxc-"
)

该示例输入了由tlfile.tlb文件定义的外部应用程序或控件的类型库接口。其它的参数定义了类型库接口所暴露的方法、属性和常量的前缀。

如果该类型库提供了一个名为AddNumbers的方法,在我们的Visual LISP代码中它将被识别为dsxm-AddNumbers。有趣的是,一旦你已经输入了类型库并且程序运行成功后,Visual LISP将识别这些外部应用程序中的所有已定义的属性、方法、常量,并将其做为内置的LISP函数把它们的代码变蓝。这也是Visual LISP IDE可以帮你编程及提高你及时发现错误的能力的另一原因。

图3-3 类型库接口

类型库仅仅是一个接口,它暴露了提供者的所有对象模型成员供给其它应用程序查询用。当加载类型库时,它立刻定义并识别相关应用程序提供者的所有公开暴露的属性、常量和方法给应用程序使用者使用。

在图3-3中,Excel类型库被加载以做便Visual LISP可以连接到Excel对象模型并使用其暴露的工具。这样可以节省你很多时间和麻烦,因为它在Excel中建立了直接的访问工具,这样就可以做你想需要的而不必尝试在Visual LISP中重复另起炉灶。下面的例子显示了它是如何使用的。

例如,当通过从Visual LISP中调用,将一个定值做为参数提供给Excel函数,你可以用常量枚举名来代替实际所代表的数值以使得你的编码清晰易懂。这也省去了你需要浏览Excel中的所有枚举并把它们翻译成Visual LISP的时间。如果Excel提供了一个如put-cellcolor的常量时,那就可以在Visual LISP中直接使用它。

Visual LISP需要类型库信息来确定对象的方法、属性和常量是否存在。有些对象不含有任何类型库信息,例如AcadDocument对象。

(vlax-typeinfo-available-p object)

如果对象的类型库信息存在,返回T。如果不存在,则返回nil。

参数:
Object – 一个vla-对象。

(defun Excel-Get-Cell (rng row column)
  (vlax-variant-value
    (msxl-get-item
      (msxl-get-cells rng)
      (vlax-make-variant row)
      (vlax-make-variant column)
    )
  )
)
(defun Excel-Put-CellColor (row col intcol / rng)
  (setq rng (Excel-Get-Cell (msxl-get-ActiveSheet xlapp) row col))
  (msxl-put-colorindex (msxl-get-interior rng) intcol)
)

上例中定义的第二个函数提供了一个在Visual LISP中对一个Excel工作表中的给定单元填色的方法。这可以通过使用Excel中已暴露接口的方法,这是通过首先加载Excel类型库实现的。这个以上显示的类型库项带有一个 msxl-前缀。

当你调用了一个类型库接口,其中涉及到的函数随后会被VLISP编辑器语法引擎识别到。当你正确地输入了它们后,它们就会改变颜色以显示它们确实被从外面的类型库接口中被视为一个有效的函数而显示出来。这是一个很有用的编码练习的基础:语法感知。

提示!类型库有很多种形式,他们通常是.TLB文件。但也可以是.OLB、.DLL,甚至是.EXE。值得一提的是Microsoft Office 97 和 2000版通常用.TLB文件,而OFFICE XP自己使用.EXE文件来对类型库提供对其它应用的接口定义。请翻阅与你准备使用外部应用程序或服务相关的参考资料以了解它是如何暴露共ActiveX类型库信息的内容。
尽管变体和安全数组数据类型这个话题在本书的前几节已经讲过,但在Visual LISP的ActiveX领域中它们具有相当重要的位置,值得我们用一整章的篇幅来专门讲解。我们将首先简要了解他们是什么,然后开始探索如何通过Visual LISP函数来使用它们。

正如我们前面提到的,变体是一种数据类型,它被设计成能包含所有任何其它数据的通用容器。他们消耗最多的内存并可处理所有的数据类型,因为他们会根据资源需求取最大内存。

象C/C++、Visual Basic以及Delphi这类语言会提供声明语句去提前通知编译器确定每个变量将包含什么数据类型。这不仅保证了精简的资源需求,同时也允许编辑期间进行错误检查,以防止运行时的问题。

Visual LISP变体函数
(vlax-make-variant [value] [type])
使用给定的值或符号赋值来创建一个变体对象

参数:
Value - 要指定给变体的值。如果省略该参数,变体将创建为 vlax-vbEmpty 类型(未初始化)。
Type – 变体的数据类型,如果省略该参数,变体将根据最接近的ActiveX数据类型来确定LISP数据类型(看下表)。

示例:
(vlax-make-variant) 或 (vlax-make-variant nil)
创建一个未初始化(vlax-vbEmpty)变体。

(vlax-make-variant 10 :vlax-vbInteger)
创建一个整型(vlax-vbInteger) 变体,其值为10。

(vlax-make-variant “vlisp example”)
创建一个字符串类型(vlax-vbString)变体,其值为“vlisp example”。

(setq dblarray (vlax-make-safearray vlax-vbDouble ‘(0 . 3)))
(vlax-make-variant dblarray :vlax-vbArray)
创建一个包含双精度值安全数组的变体。

提示!ActiveX数据类型中的十进制和短型在Visual LISP中并不支持,但当从外部资源读取值时,你可以用(vlax-variant-type)来指定其类型。将这些类型的数据发送到外部资源时,你需要使用数字表示法来替代(vlax-vbDecimal)和(vlax-vbShort),因为在Visual LISP中它们并未作为枚举提供。例如,十进制数据类型的枚举值为14。

变体数据类型
如果你不为变体构造器指定数据类型又会怎样?Visual LISP将会使用默认映射尝试将它转换到一个适当的数据类型。表6-1显示了从LISP到变体的数据类型的默认映射。

  LISP 数据类型     分配的变体默认数据类型   
  nil     vlax-vbEmpty   
  :vlax-null     vlax-vbNull   
  INT (integer)     vlax-vbLong   
  REAL (float)     vlax-vbDouble   
  STR (string)     vlax-vbString   
  VLA-OBJECT     vlax-vbObject   
  :vlax-true or :vlax-false     vlax-vbBoolean   
  VARIANT     与初始值的类型相同   
  SafeArray     vlax-vbArray   
  N/A     vlax-vbShort   
  N/A     vlax-vbDecimal   
  N/A     vlax-vbDate   


表 6-1 – Visual LISP默认LISP->变体数据类型映射

(vlax-variant-type variant)
返回变体的数据类型,如果variant不是变体,则返回错误信息。返回值是数据类型的枚举值(查看附录A的数据类型枚举值)。

参数:
Variant – 变体。

示例:
(setq vartest (vlax-make-variant 6 vlax-vbInteger))
(vlax-variant-type vartest)
返回 2 (整数类型)

(setq vartest (vlax-make-variant “dog” vlax-vbString))
(vlax-variant-type vartest)
返回 8 (字符串类型)

(vlax-variant-value symbol)
返回包含于变体符号中值。如果symbol不包含变体数据类型。则返回错误信息。

参数:
Symbol – 包含变体值的符号。

示例:
(setq vartest (vlax-make-variant “testvalue” vlax-vbString))
(vlax-variant-value vartest)
将“testvalue”值作为字符串结果返回。

(setq sa (vlax-make-safearray vlax-vbDouble ‘(0 . 2)))
(setq vartest (vlax-make-variant sa vlax-vbDouble))
(vlax-variant-value vartest)
返回#<safearray...>值,它是vla-object类型。

(vlax-safearray->list (vlax-variant-value vartest))
返回结果是(0.0 0.0 0.0)列表值。

(vlax-variant-change-type symbol type)
更改变体的数据类型。

参数:
Symbol - 变体值
Type - 要转换到的数据类型数字或枚举

示例:
(setq vartest (vlax-make-variant 5 vlax-vbInteger))
(setq vartest (vlax-variant-change-type vartest vlax-vbString))
转换vartest为字符串类型(vlax-vbString)变体,它将致使通过(vlax-variant-value)返回的值为“5”。
(vlax-make-safearray type dim1 [dim2] …)
创建一个安全数组,其数据类型为type,维度范围dim1,以此类推,可以指定额外的维度。不管什么原因,如果操作失败,语句将返回nil。

参数:
Type – 数据类型(整数或枚举)
Dim1 – 第一维数组(一维数组)
Dim2 – (可选)第二维维数(二维数组)等。

示例:
(setq sa (vlax-make-safearray vlax-vbDouble ‘(0 . 2)))
创建一个双精度的单维数组,它可容纳三个不同的元素(0,1,2)。

(setq sa (vlax-make-safearray vlax-vbString ‘(0 . 1) ‘(1 . 3)))
创建一个字符型二维数组,第一维包含两个元素,由索引0开始。第二给包含三个元素,由索引1开始。

提示!要填充安全数组,可使用(vlax-safearray-fill)还是(vlax-safearray-put-element)来填充,至于使用哪个填充,可根据用户是否需要一次只指定一个元素或一次性指定所有元素来决定。

(vlax-safearray->list symbol)
如果symbol包含安全数组,元素将转换为LISP LIST数据类型被返回。如果symbol不包含安全数组,会产生错误。你需要将对该函数的调用封装到错误捕获内以使这个错误能得到适当处理。

参数:
Symbol – 包含安全数组的符号

(vlax-safearray-type symbol)
如果symbol包含安全数组,元素的数据类型将以枚举结果返回(整数值)。这将可匹配整数或枚举结果(查看附录X有关数据类型枚举)。如果symbol不包含安全数组,将产生错误。

参数:
Symbol – 包含安全数组的符号

示例:
(setq sa (vlax-make-safearray vlax-vbdouble ‘(0 . 3)))
(vlax-safearray-type sa)
返回5(双精度),相当于vlax-vbDouble

(vlax-safearray-fill safearray ‘element-values)
指定值给安全数组内的多个元素。如果提供的参数不是一个数组,将返回ActiveX错误。你需要将对该函数的调用封装到错误捕获内以使这个错误能得到适当处理。

参数:
Safearray        安全数组类型的对象
Element-values        一个存储于数组中的值列表,你可以指定与数组中元素一样多的值。如果你指定的数值少于元素个数,剩余的元素保留他们当前值或为空。对于多维数组,element-values必须是列表的列表,每一列表对应数组的一维。

示例:
创建一个双精度值的单维数组:
_$ (setq myarray (vlax-make-safearray vlax-vbdouble '(0 . 2)))
#<safearray...>
使用vlax-safearray-fill来填充数组元素值:
_$ (vlax-safearray-fill myarray '(1 2 3))
#<safearray...>
列出数组包含的值以校验元素值:
_$ (vlax-safearray->list myarray)
(1.0 2.0 3.0)

(vlax-safearray-get-element safearray element [element...])
返回安全数组中指定元素的值,element的值是整数,表示在该数组中要取得的索引位置。如果safearray参数非安全数组对象,将产生ActiveX错误。你需要将对该函数的调用封装到错误捕获内以使这个错误能得到适当处理。

参数:
Safearray –安全数组类型的对象
Element – 整数,指要取得的索引位置

示例:
_$ (setq sa (vlax-make-safearray vlax-vbString '(1 . 2) '(1 . 2) ))
#<safearray...>
使用vlax-safearray-put-element来填充数组:
_$ (vlax-safearray-put-element sa 1 1 "A")
"a"
_$ (vlax-safearray-put-element sa 1 2 "B")
"b"
_$ (vlax-safearray-put-element sa 2 1 "C")
"c"
_$ (vlax-safearray-put-element sa 2 2 "D")
"d"
使用vlax-safearray-get-element来检索数组第一维的第二元素:
_$ (vlax-safearray-get-element sa 1 1)
”A”
_$ (vlax-safearray-get-element a 2 2)
”D"

(vlax-safearray-put-element safearray element [element...] value)
在安全数组中指定新值给单个元素。如果safearray参数不是安全数组对象,将产生ActiveX错误。如果提供的元素值不能与数组中的数据类型相匹配,将返回ActiveX错误。你需要将对该函数的调用封装到错误捕获内以使这个错误能得到适当处理。

参数:
Safearray         安全数组类型的对象
Element         指向你将指定值的元素所在位置的系列索引值。对于一维数组,指定一个索引值,对于二维数组,指定两个索引值,以此类推。
Value         指定给每个元素的值。在数组中要指定不同的值给数组中个别的元素,要分开调用独立的值来对应不同的元素位置。

示例:
_$ (setq sa (vlax-make-safearray vlax-vbString '(1 . 2) '(1 . 2) ))
#<safearray...>
使用vlax-safearray-put-element来填充数组:
_$ (vlax-safearray-put-element sa 1 1 "A")
"A"
_$ (vlax-safearray-put-element sa 1 2 "B")
"B"
_$ (vlax-safearray-put-element sa 2 1 "C")
"C"
_$ (vlax-safearray-put-element sa 2 2 "D")
"D"
你也可以用vlax-safearray-fill函数来填充数组值,以下的函数调用能和三个vlax-safearray-put-element调用一样完成同样的任务:
(vlax-safearray-fill sa '(("A" "B") ("C" "D")))

(vlax-safearray-get-dim safearray)
返回给定安全数组中的维数(数组维数的数字)。如果给定的参数不是数组,将返回ActiveX错误。你需要将对该函数的调用封装到错误捕获内以使这个错误能得到适当处理。

参数:
Safearray 安全数组类型的对象

示例:
_$ (setq myarray (vlax-make-safearray vlax-vbinteger '(2 . 5)))
#<safearray...>
_$ (vlax-safearray-get-dim myarray)
2

(vlax-safearray-get-l-bound safearray dim)
返回指定数组的维数下界(整数值)。如果给定的参数不是数组,将返回ActiveX错误。你需要将对该函数的调用封装到错误捕获内以使这个错误能得到适当处理。

参数:
Safearray – 安全数组类型的对象
Dim – 整数,数组的第几维,第一维为1

示例:
以下示例是求以下所定义的安全数组的下界值:
(vlax-make-safearray vlax-vbString '(1 . 2) '(0 . 1) ))
取得数组第一维的起始索引值(下界):
_$ (vlax-safearray-get-l-bound tmatrix 1) 1

(vlax-safearray-get-u-bound safearray dim)
返回指定数组维度的上界(整数值)。如果指定的参数不是数组,将返回ActiveX错误。你需要将对该函数的调用封装到错误捕获内以使这个错误能得到适当处理。

参数:
Safearray – 安全数组类型的对象
Dim – 整数,数组的第几维,第一维为1。

(setq sa (vlax-make-safearray vlax-vbString '(1 . 2) '(0 . 1) ))
_$ (vlax-safearray-get-u-bound sa 1)
2
第一维的上界的索引值为2。

取得数组第二维的上界索引值,其值为1:
_$ (vlax-safearray-get-u-bound sa 2) 1
Visual LISP提供了一系列用于创建、操控和关闭ActiveX对象的函数。这通常是对外部应用程序会话对象而言的,但它同时也可以适用于任何外部进程对象,如DLL或OCX接口。

(vlax-get-object program-id)
尝试连接到存在的对象(进程),与Visual Basic/VBA函数GetObject (program-id)相同。

参数:
Program-ID – 字符串,应用对象类标识符的名称。例如“Word.Application”或“Excel.Application”。

示例:
(setq xlapp (vlax-get-object “Excel.Application”))
成功时返回外部Excel应用程序进程的vla-对象,否则返回nil。

(vlax-create-object program-id)
尝试创建一个新的对象会话(进程)。与Visual Basic函数CreateObject (program-id)相同。

参数:
Program-ID – 字符串,应用程序对象类标识符名称。例如“Word.Application”或“Excel.Application”。

示例:
(setq xlapp (vlax-create-object “Excel.Application”))
成功时返回新的外部Excel应用程序进程的vla-对象,否则返回nil。

(vlax-get-or-create-object program-id)
尝试先连接到存在的对象会话,然后,如果找不到,就尝试创建一个新的对象会话。这个函数在Visual Basic中没有对应的函数,它是Visual LISP中特有的。

参数:
Program-ID – 字符串,指应用程序对象类标识符名称。例如“Word.Application”或“Excel.Application”。

示例:
(setq xlapp (vlax-get-or-create-object “Excel.Application”))
成功时返回外部Excel应用程序对象的vla-对象,否则返回nil。

(vlax-write-enabled-p object)
如果object可以修改则返回T,否则返回nil。

备注:请小心该函数。在对象实际上是开放可修改状态下,有时它会返回False。

参数:
Object – 任何Vla-对象

(vlax-object-erased-p object)
如果object在图中已经被删除则返回T,否则返回nil。

参数:
Object – 任何代表图元对象类型的vla-对象。

(vlax-release-object object)
从内存中释放对象。它不是重新分配内存。当释放一个指向外部应用程序会话的对象时,这里强烈建议使用(gc),它能从操作系统资源中强行释放外部进程。

参数:
Object – 任何vla-对象。

警告!尽管对象符号是局部的,函数用完后不一定要释放对象的资源。但还是建议当已经不需要这个对象时可使用该函数以确保释放对象。然而,需要提醒的是,既使是释放了由外部应用程序驱动的对象,它也可能没有从内存或操作系统进程堆栈中被全部释放。最好是在你完成代码后释放所有不再使用的对象,然后再调用(gc)函数去强制回收内存堆栈。

Visual LISP提供的最有用的函数是文件和目录函数。这些函数集可用于访问和修改文件属性,以及列出指定文件夹中的文件及文件夹。使用这些函数的一个例子,是将其用于对话框的列表框的环境中。

可能你喜欢在列表框中显示图纸文件清单,而不显示其扩展名(这样的名称会短一些)。就可结合目录列表框和vl_filename-base函数来实现,如下所示:
(mapcar ‘vl-filename-base (vl-directory-files pathname “*.dwg”))

这样将返回名称的列表,如(“图形1”“图形2”…)。注意在这个例子中并没有提供错误检查。如果(vl-directory-files)函数返回nil,其余的语句就会因出错而崩溃。该例只是用来证明这些函数是如何相结合并用于使文件和目录的信息更容易使用。

(vl-file-size filename)
以整数形式返回filename的字节数。如果没找到文件名,就返回nil。

参数:
Filename 字符串,指要查询文件的名称。

示例:
(vl-file-size “c:\\myfile1.txt”); 返回 125523 (大约 124 Kb)

(vl-file-copy source-filename target-filename [append])
从源位置(source-filename)复制文件到目标位置(target-filename)。如果append为非nil,同时目标文件存在,源文件就会被添加到已存在的目标文件。如果目标文件存在而append为nil,该文件将不被复制同时返回值为nil。如果成功,将返回整数值。

参数:
Source-filename 被复制文件的名称,如果文件不在默认的搜索路径中,则该文件名必须包含完整的路径位置。
Target-filename 源文件要复制到的目标名称。如果目标路径未指定,则使用默认的工作目录位置。
Append (可选)如果是非nil,代表如果目标文件存在,源文件将会被附加到目标文件上去。

示例:
(vl-file-copy “c:\\myfile1.txt” “c:\\mycopy.txt”)
(vl-file-copy “c:\\myfile2.txt” “c:\\mycopy.txt” T); 添加目录文件


(vl-file-delete filename)
删除文件名。如果成功返回T,否则返回nil。

参数:
Filename 字符串,指要删除的文件的名称。

(vl-file-rename old-name new-name)
重命名现有的文件,由old-name重命名为new-name。如果成功返回T,否则返回nil。

参数:
Old-Name 字符串,指现有文件的名称。
New-Name 字符串,指重命名后的文件名称。

(vl-file-directory-p filename)
如果filename是目录文件夹名称则返回T,如果filename实际上是一个文件或根本不存在,则返回nil。

(vl-file-systime filename)
返回文件最后修改的日期和时间值列表。返回的列表为(年 月 星期 日  时 分 秒)的格式。

(vl-filename-base filename)
返回不带路径和扩展名返回基本文件名。

参数:
Filename 字符串,指文件名,可带或不带路径和扩展名。

示例:
(vl-filename-base “c:\\myfiles\\drawing1.dwg”)
返回“drawing1”
(vl-filename-base “drawing1.dwg”)
返回“drawing1”


(vl-filename-directory filename)
从指定的filename字符串返回目录或路径前缀值。

参数:
Filename 字符串,指包含路径的文件名。

示例:
(vl-filename-directory “c:\\dwgfiles\\working\\drawing1.dwg”)
返回: “c:\\dwgfiles\\working”


(vl-filename-extension filename)
返回给定文件名字符串的扩展名。

参数:
Filename 字符串,指文件名称。

示例:
(vl-filename-extension “c:\\myfiles\\drawing1.dwg”)
返回 “dwg”


(vl-filename-mktemp [pattern directory extension])
创建一个用于临时文件的独特文件名。返回代表文件名称的字符串,格式为:directory\base<XXX><.extension>。其中base多达5个字符,由pattern中取得,XXX是一个3字符的独特组合。

所有在VLISP会话中由vl-filename-mktemp生成的文件名都会在你退出VLISP会话时被删除。

参数:
Pattern 字符串,包含了文件名样式;如果nil或缺省,vl-filename-mktemp就用“$VL~~”。
Directory 字符串,临时文件目录的名称;如果nil或缺省,vl-filename-mktemp就在以下顺序中选择一个目录:
■如果在pattern已指定目录,就用它。
■在TMP环境变量中指定的目录。
■在TEMP环境变量中指定的目录。
■当前目录。
Extension 字符串,指定给文件的扩展名;如果nil或缺省,vl-filename-mktemp使用pattern中的扩展名部分(有可能是空字符串)。

示例:
(vl-filename-mktemp)
"C:\\TMP\$VL~~004"
(vl-filename-mktemp "myapp.del")
"C:\\TMP\\MYAPP005.DEL"
(vl-filename-mktemp "c:\\acad2002\\myapp.del")
"C:\\ACAD2002\\MYAPP006.DEL"
(vl-filename-mktemp "c:\\acad2002\\myapp.del")
"C:\\ACAD2002\\MYAPP007.DEL"
(vl-filename-mktemp "myapp" "c:\\acad2002")
"C:\\ACAD2002\\MYAPP008"
(vl-filename-mktemp "myapp" "c:\\acad2002" ".del")
"C:\\ACAD2002\\MYAPP00A.DEL"


(vl-directory-files path pattern [mode])
按照不同的模式,返回文件或子文件夹的列表。

参数:
Path 字符串,指要查询的路径名。
Pattern 字符串,指要查询文件。可以包含通配符。如果不指定或nil,则使用“*.*”
Mode (可选)整数。以下其中一个…
-1 = 只列出目录名
0 =  列出文件及目录(未指定时的默认值)
1 =  只列出文件

示例:
命令: (vl-directory-files “c:\\dwgfiles\\Working” “*.dwg”)
(“drawing1.dwg” “drawing2.dwg” . . .)
命令: (vl-directory-files “c:\\dwgfiles” nil -1)
(“.” “..” “Finished” “Working”)
命令: (vl-directory-files “c:\\dwgfiles” nil 1)
nil
AutoLISP提供了大量强大的映射和循环函数,如(while)(foreach)(mapcar)(apply)。而Visual LISP也增加了一些更适合用于与ActiveX集合对象的函数。这些函数包括有(vlax-for)(vl-every)(vlax-map-collection)等等。

(vlax-map-collection object function)
应用function到集合对象的成员(对象),如果对象不是集合,则生成错误。

参数:
Object 代表集合的vla对象。
Function 用于对象的符号或lambda表达式。

示例:
(setq docs (vla-get-documents (vlax-get-acad-object)))
(vlax-map-collection docs ‘vlax-dump-object)
这将重复每个已打开文件并列表所有特性...
; IAcadDocument: An AutoCAD drawing
; 特性值:
; Active (RO) = -1
; ActiveDimStyle = #<VLA-OBJECT IAcadDimStyle 046bb644>
; ActiveLayer = #<VLA-OBJECT IAcadLayer 046bbd84>
; ActiveLayout = #<VLA-OBJECT IAcadLayout 046b8a64>
; ActiveLinetype = #<VLA-OBJECT IAcadLineType 046b89b4>
… 还有其它…


(vlax-for symbol collection [expression1 [expression2]]…)
循环集合的成员对象并对每一成员对象执行语句。如果第二个参数不是集合对象,将生成错误。引用的symbol是局部的和临时的,就如(foreach)一样。

参数:
Symbol 指定给集合中每个vla对象的符号。
Collection 代表集合的vla对象
Expressions 求值的一个或多个语句(可选项)

示例:
(setq acad (vlax-get-acad-object))
(setq layers (vla-get-layers (vla-get-activedocument acad)))
(vlax-for eachLayer layers
  (princ (vla-get-name eachLayer))
  (terpri)
)

这将在命令提示处列出活动图形中所有图层的名称。

(vl-position item list)
找到时返回在list中item的第n个位置。如果list中未找到item,则返回nil。第一元素的位置索引为零(0)。

参数:
Item  任何符号或值。
List  值或符号列表。

示例:
(setq mylist ‘(“A” “B” “C”))
(vl-position “B” mylist) 返回 1
(vl-position “b” mylist) 返回 nil


(vl-every predicate-function list...)



      vl-every 函数将每个表的第一个元素作为参数(如果有多个表则形成参数表)传递给测试函数,然后传递每个表中的下一个元素,以此类推,直至其中一个表到达结束处为止。



      参数:


      Predicate-function测试函数。它可以是任何一个函数:参数个数和 vl-every 提供的表的个数一致,且对任何用户指定条件返回T。如果 predicate-function 结合每个元素后均返回非 nil 值,函数返回 T,否则返回 nil。



      predicate-function 的值可以采用下列格式之一:



      ■符号(函数名)



      ■(function(lambda(A1 A2)...))



      List(s) 被测试的列表。




      示例:



      在给定的文件夹中检查大于1024字节的文件:

(vl-every
  (function
    (lambda (filename)
      (> (vl-file-size filename) 1024)
    )
  )
  (vl-directory-files nil nil 1)
)
T




      对比两个表...

(vl-every '= '(1 2) '(1 3))
返回 nil
(vl-every '= '(1 2) '(1 2 3))
返回 T



      第一个表达式返回 nil,因为 vl-every 比较两个表中的第二个元素,而它们在数值上并不相等。第二个表达式返回 T,因为
vl-every


      在处理完较短的表 (1,2) 中所有元素后即停止比较,而直到这时为止,两个表是相等的。如果到达了表的结束处,则
vl-every



      返回非 nil 值。
_<span tabindex="0" class="MathJax" id="MathJax-Element-1-Frame" role="presentation" style="margin: 0px; padding: 0px; display: inline; font-style: normal; font-weight: normal; line-height: normal; font-size: 14px; text-indent: 0px; text-align: left; text-transform: none; letter-spacing: normal; word-spacing: normal; overflow-wrap: normal; white-space: nowrap; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border: 0px; position: relative;" data-mathml='(setq list1 (list 1 2 3 4))  (1 2 3 4)  _'>(setq list1 (list 1 2 3 4))  (1 2 3 4)  _(setq list1 (list 1 2 3 4))  (1 2 3 4)  _ (setq list2 nil)
nil
_$ (vl-every '= list2 list1)
T




      返回值为 T,因为
vl-every



      处理 nil 表时,假定已经到达了表的结束处(尽管没有对其中任何元素应用论断)。既然如此,
vl-every


    将返回非 nil 值。
(vl-load-all filename)


      在同一时间内加载命名的VLX文件到所有打开的文档中。它还会加载那些在同一
AutoCAD



      应用程序会话中后续打开的任何文档中。



      参数:


      Filename 符号或字符串,代表有效的文件名。

(vl-propagate ‘symbol)



      在AutoCAD应用程序名称空间中复制符号和与其相关的值到所有打开的文档中去,以及在同一AutoCAD应用程序会话中后续打开的任何文档中。



      参数:



      Symbol 一个引用符号的名称。

(vl-bb-set ‘symbol)




      张贴符号及其相关的值到黑板名称空间。黑板名称空间是AcadApplication名称空间的一部分,它可被所有在Documents集合中打开的文件访问。这提供了与Windows粘贴板相似的功能,不过它只用于张贴和取回LISP符号而已。



      参数:



      Symbol 一个引用符号的名称。

(vl-bb-ref ‘symbol)



      从黑板名称空间取回符号及其相关的值。



      参数:



      Symbol 一个引用符号的名称。

(vl-list-exported-functions)



      返回那些由任何已加载的VLX应用程序显露给文档名称空间的所有函数的表。

(vlax-add-cmd “globalname” ‘function [“localname” | flags])



      将VLX应用程序中使用(defun)方式而未定义为C:的函数定义为命令行函数。你必须至少要指定globalname和function项。localname和flags项是可选的。你不能将(vlax-add-cmd)用于显露那些创建反应器对象或充当反应器回调的函数显示为命令。如果成功返回globalname值,不成功则返回nil。



      推荐从独立名称空间VLX使用vlax-add-cmd函数。然后使用APPLOAD命令明确加载VLX,这样比将LISP文件放到启动组好。



      参数:



      GlobalName 字符串,在命令提示符中指定的命令名称。



      Function 代表函数名称的引用符号。



      LocalName (可选项) VLX应用程序名称空间内部的命令名称。如果省略,默认为GobalName。



      Flags (可选项)修改关于透明、pickset和pickfirst等项命令行为。

主要标志选项:
ACRX_CMD_MODAL



      (0) 在使用其他命令时不能调用该命令。

ACRX_CMD_TRANSPARENT



      (1) 在使用其他命令时可以调用该命令。

二级标志选项:
ACRX_CMD_USEPICKSET



      (2) 检索选择优先集时,在 AutoCAD 中清除设置。命令能够获取优先集,但不能检索或设置夹点。

ACRX_CMD_REDRAW



      (4) 检索选择优先集或夹点集时,不将它们从 AutoCAD 中清除。命令可获取优先集和夹点集。



      如果同时设置了 ACRX_CMD_USEPICKSET 和 ACRX_CMD_REDRAW,则效果和仅设置 ACRX_CMD_REDRAW 一样。关于标志的详细信息,请参见 《ObjectARX 参考手册》中的“Command Stack”。



      示例:



      在Transparent.VLX中定义并加载到AutoCAD中的函数:

(vl-load-com)
(vl-doc-export ‘example1)
(defun example1 ()
   (princ “\这是一个透明函数的示例。”)
   (princ)
)   
(vlax-add-cmd “example1” ‘example1 “example1” ACRX_CMD_TRANSPARENT)
(princ)
命令: LINE
指定第一点: ‘EXAMPLE1
这是一个透明函数的示例。
重新回到LINE命令。
指定第一点:

(vlax-remove-cmd “globalname”)



      删除之前用(vlax-add-cmd)定义的命令定义。函数本身并不受影响,但是命令提示符接口从命令组中被删除了。



      参数:



      GlobalName 字符串,指要删除的命令名称。



      示例:

(vlax-remove-cmd “example1”)
T
(vlax-remove-cmd “example2”)
nil

(vl-acad-defun ‘function)



      使 (defun)的LISP函数能作为C:函数给ObjectARX应用程序调用。



      这使函数可以经由ObjectARX应用程序访问。



      参数:



      Function 代表函数名称的引用符号。


      示例:
(vl-acad-defun ‘example1)
(vl-acad-undefun ‘function)



      取消一个之前用(vl-acad-defun)函数显露的命令。如果成功则返回T,否则返回nil。



      参数:



      Function 代表函数名称的引用符号。



      示例:

(vl-acad-undefun ‘example1”)
T



Visual LISP提供了专门的函数用于访问和修改Windows注册表。你可以用这些函数在本地注册表的HKEY_LOCAL_MACHINE和HKEY_CURRENT_USER单元中查询和修改注册表项。你不能使用Visual LISP注册表函数来访问远程注册表,也不能用Visual LISP来访问HKEY_USERS和HKEY_CLASSES_ROOT以及HKEY_CURRENT_CONFIG注册表单元。

注意,即使在Visual LISP可以访问的注册表单元,你仍会受限于进程所有者的安全环境以致限制了你的访问。换句话说,如果Visual LISP应用程序是被一个对这台机器权限有限的用户使用时,有些注册表项可能无法访问或不能被Visual LISP修改。这个问题在网络环境中需要重点考虑,因为它的组策略会修改注册表的访问许可。

(vl-registry-read regkey [value-name])
如果注册表中有定义注册表项或注册表值名(符号),则返回值指定给一个明确的注册表项或注册表值名(符号)的值。如果未找到该注册表项或值名,则结果就为nil。

参数:
RegKey 在HKEY_LOCAL_MACHINE或HKEY_CURRENT_USER单元中的注册表项名称。
Value-Name (可选项)在指定注册表项下方的从属值名(符号)的名称。

示例:
(vl-registry-write “HKEY_CURRENT_USER\\Example1” “FOO” “123”)
“123”
(vl-registry-read "HKEY_CURRENT_USER\\Example1" “FOO”)
“123”
(vl-registry-read “HKEY_CURRENT_USER\\Example1”)
nil
(vl-registry-write "HKEY_CURRENT_USER\\Example2" "" "ABCDEF")
"ABCDEF"
(vl-registry-read "HKEY_CURRENT_USER\\Example2")
"ABCDEF"


(vl-registry-write regkey [value-name] value)
将值写入注册表项或注册表项的值名中去,如果成功返回值。如果不成功则返回nil。

参数:
RegKey 注册表项的名称。
Value-Name (可选项)在指定注册表项下方的从属值名(符号)的名称。
Value 写入到指定的注册表项或值名的值。

示例:
(vl-registry-write “HKEY_CURRENT_USER\\Example1” “TEST1” “123”)
“123”
(vl-registry-write “HKEY_CURRENT_USER\\Example1” “” “456”)
“456”

(vl-registry-delete regkey [value-name])
删除注册表中指定位置的注册表项及其相关的值,成功时返回T,如果失败则返回nil。如果提供了value-name且不为nil,指定的值将被从注册表中清除。如果没有value-name或为nil,该函数将删除指定注册表项及它的所有值。如果注册表中下面有子注册表项存在,该注册表项将不能被删除。要删除含有子注册表项的注册表项,你必须先用(vl-registry-descendents)来收集子注册表项并先将它们删除。

参数:
RegKey 注册表项的名称。
Value-Name (可选项)在指定注册表项下方的从属值名(符号)的名称。

示例:
(vl-registry-write "HKEY_CURRENT_USER\\Example1" "TEST1" "123")
"123"
(vl-registry-delete "HKEY_CURRENT_USER\\Example1")
T

(vl-registry-descendents regkey [value-names])
返回指定注册表项下属的子项或值名的表。如果提供了value-names且不为nil,将从注册表中列出指定的值名。如果没有value-names或为nil,该函数则显示注册表项的所有子项。还要注意到,返回的值经常是按倒序排列。

参数:
RegKey 注册表项名称。
Value-Names 包含regkey入口的数值的字符串。

示例:
(vl-registry-descendents "HKEY_LOCAL_MACHINE\\SOFTWARE")
("WexTech Systems" "Voice" "Synaptics" "Symantec" "Secure" "Program Groups" "Policies" "ODBC" "Nico Mak Computing" "MicroVision" "Microsoft" "MetaStream" "McNeel" "McAfee" "JavaSoft" "Intel Corporation" "INTEL" "InstalledOptions" "Helios" "DOSLib" "Dell Computers" "Dell Computer Corporation" "Dell Computer" "DameWare Development" "Clients" "Classes" "BVRP Software" "BigFix" "Autodesk" "ATI Technologies" "Apple Computer, Inc." "America Online" "Adobe" "Adaptec" "3Com")

你可打开AutoCAD安装程序的Visual LISP样板目录下的RegDump.LSP文件,可看到注册表函数的更多例子。在这个文件中,你可以找到一个名为(registry-tree-dump)的有用函数,它对指定注册表项执行递归来搜索到其下级的所有子项和值名。

提示:你可以创建一对Get和Set函数来保存和恢复注册表值,用于控制标准位置和错误捕获。你应该会发现以下两个函数是很有用的:

(setq G<span tabindex="0" class="MathJax" id="MathJax-Element-2-Frame" role="presentation" style="margin: 0px; padding: 0px; display: inline; font-style: normal; font-weight: normal; line-height: normal; font-size: 14px; text-indent: 0px; text-align: left; text-transform: none; letter-spacing: normal; word-spacing: normal; overflow-wrap: normal; white-space: nowrap; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border: 0px; position: relative;" data-mathml='REGROOT"HKEYCURRENTUSERSoftwareMyApplication")(defunRegGet(keydefault/val)(if(=nil(setqval(vl&#8722;registry&#8722;read(strcatG'>REGROOT"HKEYCURRENTUSERSoftwareMyApplication")(defunRegGet(keydefault/val)(if(=nil(setqval(vl&#8722;registry&#8722;read(strcatGREGROOT"HKEYCURRENTUSERSoftwareMyApplication")(defunRegGet(keydefault/val)(if(=nil(setqval(vl&#8722;registry&#8722;read(strcatGREGROOT key))))
    (progn
      (regset key default)
(setq val (vl-registry-read (strcat G<span tabindex="0" class="MathJax" id="MathJax-Element-3-Frame" role="presentation" style="margin: 0px; padding: 0px; display: inline; font-style: normal; font-weight: normal; line-height: normal; font-size: 14px; text-indent: 0px; text-align: left; text-transform: none; letter-spacing: normal; word-spacing: normal; overflow-wrap: normal; white-space: nowrap; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border: 0px; position: relative;" data-mathml='REGROOTkey)))))(ifvalvaldefault))(defunRegSet(keyval)(vl&#8722;registry&#8722;write(strcatG'>REGROOTkey)))))(ifvalvaldefault))(defunRegSet(keyval)(vl&#8722;registry&#8722;write(strcatGREGROOTkey)))))(ifvalvaldefault))(defunRegSet(keyval)(vl&#8722;registry&#8722;write(strcatGREGROOT key) "" val)
)



评分

参与人数 1明经币 +1 收起 理由
lucas_3333 + 1 神马都是浮云

查看全部评分

"觉得好,就打赏"
还没有人打赏,支持一下
发表于 2019-5-29 12:54 来自手机 | 显示全部楼层
总结得很好
发表于 2019-5-30 15:07 | 显示全部楼层
总结的很好,知识讲的很全面
发表于 2019-6-23 10:52 | 显示全部楼层
路过,,,,留下脚印,收藏下
发表于 2019-6-24 09:04 来自手机 | 显示全部楼层
好极了,可以细品
发表于 2019-7-20 05:25 | 显示全部楼层
用心了。
总结全面、详细。
发表于 2019-7-21 11:04 | 显示全部楼层
学习了,谢谢!
发表于 2019-7-21 23:27 来自手机 | 显示全部楼层
学习了谢谢
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2024-4-19 14:10 , Processed in 0.449088 second(s), 30 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表