第三章 在Visual LISP中使用ActiveX (一)对象模型
第三章 在Visual LISP中使用ActiveX在本章中,我们将更多讨论有关在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:DUMP (/ 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)
所有这些语句都将完成同样的事情。
属性的名称并不要求区分大小写,但本书的例子都将首字母大写,以示清晰。总的来说,你会发现以上前两项都很好用,但也有情况是要求用到后两项。特别是涉及到象MicrosoftExcel 或 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 ...) 或
(vla-method object arguments) 或
(vlax-invoke object method ...)
调用关联于对象的方法并为方法提供任何所需的参数。如果成功,将返回结果。如果对象没有提供对应的方法,将会产生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))
)
)
)
当试图在方法上使用这种方式时要特别小心,因为方法的参数列表会随着对象和方法的变化而变化。有一些方法不需要参数,而另一些则随长度变化。
http://bbs.mjtd.com/xwb/images/bgimg/icon_logo.png 该贴已经同步到 明经通道的微博 这个好好学习下 打卡,属性后面的括号(RO)代表该属性为只读,在这里,所有的属性均为只读,方法后面括号内的数字表示了每一方法所需要的参数数目 好文章,你们是读,而我的水平只能一遍遍的研读 老大辛苦了。 The Visual Developer's Bible(2nd Edition)
中文版? 什么时候出书 呢 先收藏了,谢谢版主。 紧跟教程学习 跟帖学习。 越来越吃力,看不懂了 看不出来,还是oo的语言啊。。 学习中!!