使用反应器清华CAD二次开发LISP.ppt
第 11 章 使用反应器,11.1 反应器 反应器是一种反馈机制,它可以在发生某些特定事件时,将所发生的事件通知给应用程序,应用程序将会根据发生的具体事件做出相应的决策。例如,在某个图元上链接了一个反应器,如果用户移动这个图元,应用程序就会接到反应器的通知,知道了该图元被移动这个事件,如果需要,应用程序可以用适当的动作(如移动与该图元相关的其它图元,或显示有关信息等)响应该通知。1.反应器的类型 反应器有多种类型,每种反应器对应一个或多个AutoCAD事件。反应器可以分为以下几个大类:l数据库反应器:当图形数据库发生特定类型的事件时,该反应器将通知应用程序。,l文档反应器:当前图形文档发生改变(如打开新的图形文档、激活其它文档窗口、改变文档的锁定状态等)时,该反应器将通知应用程序。l编辑器反应器:在调用AutoCAD命令(如打开图形、关闭图形、保存图形、输入输出DXF文件、改变系统变量的值等)时,该反应器将通知应用程序。l链接反应器:当加载和卸载ARX应用程序时,该反应器将通知应用程序。l对象反应器:当特定对象(AutoCAD图元)被修改、复制或删除时,该反应器将通知应用程序。调用函数vlr-types可返回反应器类型的完整列表。表11-1列出了AutoCAD反应器类型及其标识符。,表11-1AutoCAD反应器类型及其标识符,反应器类型的标识符 说明:VLR-AcDb-Reactor 数据库反应器:VLR-DocManager-Reactor 文档管理反应器:VLR-Editor-Reactor 通用编辑器反应器:VLR-Linker-Reactor 链接反应器:VLR-Object-Reactor 对象反应器,其中通用编辑器反应器被进一步细分为更加明确的几种反应器类型,见表11-2。表11-1中的通用编辑器反应器类型只是为了向后兼容才保留的,表11-2所示的各种编辑类型的反应器不能被通用编辑器:VLR-Editor-Reactor引用。,表11-2 编辑类型的各种反应器及其标识符,反应器类型的标识符 说明:VLR-Command-Reactor 通报命令事件:VLR-DeepClone-Reactor 通报 deep clone 事件:VLR-DWG-Reactor 通报打开或关闭图形文件的事件:VLR-DXF-Reactor 通报和读写 DXF 文件相关的事件:VLR-Insert-Reactor 通报和插入块有关的事件:VLR-Lisp-Reactor 通报 LISP 事件:VLR-Miscellaneous-Reactor(表中未列出的)其它编辑器反应器类型:VLR-Mouse-Reactor 通报鼠标事件(例如双击):VLR-SysVar-Reactor 通报对系统变量的修改:VLR-Toolbar-Reactor 通报对工具栏上位图的修改:VLR-Undo-Reactor 通报 undo 事件:VLR-Wblock-Reactor 通报和写块有关的事件:VLR-Window-Reactor 通报和移动或改变AutoCAD窗口大小的事件:VLR-XREF-Reactor 通报附着或修改 XREF 有关的事件,3.反应器回调事件 大部分AutoCAD操作都会产生一些特定的事件,这些事件能够用来触发反应器的动作,这样的事件被称为回调事件。例如,当发出Save命令保存图形时,将会发生AutoCAD保存图形文件(:vlr-beginSave)的事件,当保存过程结束时,将会发生AutoCAD已将当前图形保存到磁盘(:vlr-saveComplete)的事件。设计基于反应器的应用程序就是根据回调事件的内容编写这些事件发生时所要激活的函数。vlr-reaction-names函数返回与给定反应器类型相关的所有事件组成的表:(vlr-reaction-names reactor-type)参数reactor-type是反应器类型的标识,见表11-1和表11-2。,例如,下列代码将返回和图形反应器相关的所有事件组成的表:(vlr-reaction-names:VLR-DWG-Reactor)返回(:VLR-beginDwgOpen:VLR-endDwgOpen:VLR-dwgFileOpened:VLR-databaseConstructed:VLR-databaseToBeDestroyed:VLR-beginSave:VLR-saveComplete:VLR-beginClose)下列代码将返回和对象反应器相关的所有事件组成的表:(vlr-reaction-names:vlr-object-reactor);返回(:VLR-cancelled:VLR-copied:VLR-erased:VLR-unerased:VLR-goodbye:VLR-openedForModify:VLR-modified:VLR-subObjModified:VLR-modifyUndone:VLR-modifiedXData:VLR-unappended:VLR-reappended:VLR-objectClosed),加载并运行以下代码,将会打印出所有相关反应器事件的列表(按反应器类型排序)。(defun print-reactors-and-events()(foreach rtype(vlr-types)(princ(strcat n(vl-princ-to-string rtype)(foreach rname(vlr-reaction-names rtype)(princ(strcat nt(vl-princ-to-string rname)(princ)AutoLISP Reference列出了与各种反应器类型相关的所有事件,有关信息在创建反应器的函数部分做了说明。和ActiveX一样,必须首先调用vl-load-com函数,加载支持反应器和其它AutoLISP扩展函数之后,才能实现反应器的功能。,11.2 定义反应器的回调函数 反应器的回调函数就是回调事件发生时所要执行的函数。反应器的回调函数是用AutoLISP定义的。编写回调函数有以下一些限制:不能使用command函数调用AutoCAD命令,只能用ActiveX函数访问图形对象。不能使用entget和entmod函数。不能使用选择集操作函数。不能使用交互输入函数。在事件处理函数中不要加载警告和信息之外的对话框。定义对象反应器回调函数和定义其它反应器的回调函数也不完全相同。,11.2.1 定义对象反应器的回调函数定义对象反应器的回调函数的格式如下:(defun function(notifier-object reactor-object parameter-list)参数notifier-object是事件发生的对象。参数reactor-objec是调用这个函数的反应器对象。参数parameter-list是回调事件返回的回调数据表。例如,例11-1定义了名为print-radius的回调函数。notifier-object是事件发生的对象,reactor-object是调用这个函数的反应器对象,parameter-list是回调事件返回的回调数据表。虽然在本例并不关心parameter-list的值,但定义回调函数时,也要进行变量声明。,【例11-1】定义名字为print-radius的回调函数,该函数用来打印圆的半径。(defun print-radius(notifier-object reactor-object parameter-list)(vl-load-com)(cond(vlax-property-available-p notifier-object Radius);判断该图形对象是否具有radius特性(princ“这个圆的半径是:)(princ(vla-get-radius notifier-object),11.2.2 定义其它反应器的回调函数 由于其它反应器不需要链接到AutoCAD图元上,因此定义其它反应器的回调函数只需要以下两个参数:(defun function(reactor-object parameter-list)参数reactor-object是调用这个函数的反应器对象。参数parameter-list是回调事件返回的回调数据表。例11-2定义了名为saveDrawingInfo的回调函数。参数calling-reactor是调用该函数的反应器对象。参数commandInfo是回调事件返回的回调数据表。该函数在发生保存AutoCAD图形的事件时将被激活,显示文件的路径和大小等信息。,【例11-2】定义名字为saveDrawingInfo的回调函数。(defun saveDrawingInfo(calling-reactor commandInfo/dwgname filesize)(vl-load-com)(setq dwgname(cadr commandInfo)filesize(vl-file-size dwgname)(alert(strcat 这个文件(dwgname)的大小是(itoa filesize)字节.)(princ)在该例中,通过函数vl-file-size获取图形文件的大小,通过警告对话框显示这些信息。,11.2.3.AutoCAD预定义的回调函数 AutoCAD提供了两个预定义的回调函数,可以在测试反应器时使用这些函数:(1)vlr-beep-reaction函数vlr-beep-reaction的功能是让计算机发出“嘟嘟”声。(2)vlr-trace-reaction函数vlr-trace-reaction函数的功能是将参数列表打印到VLISP的“跟踪”窗口。,11.3 创建反应器 创建反应器的主要工作就是将事件和回调函数相关联。创建反应器用vlr-reactor函数。每种类型的反应器都有一个与之对应的用于创建该反应器的AutoLISP函数,这些函数的名称和反应器类型的名称相同,只是没有前面的冒号。例如,vlr-acdb-reactor为创建数据库反应器函数,vlr-toolbar-reactor为创建工具栏反应器函数。所有创建反应器的构造函数都返回一个反应器对象。AutoLISP Reference列出了与每种反应器类型相关的所有可能事件。例如,通过vlr-DWG-reactor条目,可看到表11-3所示与DWG反应器相关的所有可能事件。,表11-3 DWG反应器事件,事件名称 说明:vlr-beginClose 图形数据库将被关闭。:vlr-databaseConstructed 已经构建图形数据库。:vlr-databaseToBeDestroyed 将从内存中删除图形数据库的内容。:vlr-beginDwgOpen AutoCAD将打开图形文件。:vlr-endDwgOpen AutoCAD已结束打开操作。:vlr-dwgFileOpened 新图形已被加载到AutoCAD图形窗口。:vlr-beginSave AutoCAD将保存图形文件。:vlr-saveComplete AutoCAD已将当前图形保存到磁盘。,创建对象反应器 因为对象反应器必须链接到特定的AutoCAD图元(对象)上,所以在定义对象反应器时,必须指定反应器所要链接的图元。创建对象反应器通过函数vlr-object-reactor,该函数的调用格式如下:(vlr-object-reactor owners data callbacks)参数owners为VLA对象表,表内可以是多个VLA对象。这些对象也被称为反应器的所有者。参数data为与反应器对象相关联的数据,如果没有数据则该项为nil。参数callbacks为点对表,用于指明事件和与该事件相关联的回调函数。点对表的格式如下:(event-name.callback_function)该点对表的event-name是表11-4所示Object事件中的名称标识,callback_function为回调函数。表11-5是针表11-4所示对特定的回调事件返回的回调数据表。该函数的返回值为reactor_object(对象反应器)。,名称标识 事件:vlr-cancelled 对对象的修改已经取消。:vlr-copied 对象已被复制。:vlr-erased 对象的删除标志已被设置。:vlr-unerased 对象的删除标志已被重置。:vlr-goodbye 即将从内存中删除对象。:vlr-openedForModify 即将修改对象。:vlr-modified 对象已被修改。如果取消修改,还将激发:vlr-cancelled 和:vlr-modifyUndone。:vlr-subObjModified 对象的子图元已被修改。在修改多段线或网格顶 点时触发该事件。:vlr-modifyUndone 对象的修改已被放弃。:vlr-modifiedXData 对象的扩展图元数据已被修改。:vlr-unappended 已从图形数据库中拆离对象。:vlr-reappended 对象已被重新链接到图形数据库。:vlr-objectClosed 对对象的修改已经完成。,表11-4 Object事件及其名称标识,名称 表长度 参数:vlr-cancelled 0:vlr-erased:vlr-unerased:vlr-goodbye:vlr-openedForModify:vlr-modified:vlr-modifyUndone:vlr-modifiedXData:vlr-unappended:vlr-reappended:vlr-objectClosed:vlr-copied 1 由复制操作创建的对象(ename)。:vlr-subObjModified 1 已被修改的子对象(ename)。,表11-5 Object 事件回调数据,例如,下面的代码创建了一个对象反应器。该对象反应器只有一个所有者,即VLA对象myCircle;与该反应器对象相关联的数据为Circle Reactor;点对表为(:vlr-modified.print-radius),当发生myCircle对象被修改(即:vlr-modified)事件时,调用print-radius回调函数:(setq circleReactor(vlr-object-reactor(list myCircle)Circle Reactor(:vlr-modified.print-radius)上述反应器对象赋给了变量circleReactor。可以通过该变量实现对该反应器的查询、修改或删除等。,创建对象反应器除了必须指定反应器所要链接的图元之外,还要注意以下几点:(1)在定义所有者列表时,只能指定VLA对象,而不允许使用ename对象。要求VLA对象是因为回调函数只能用ActiveX方法修改AutoCAD对象,而ActiveX方法要求使用VLA对象。尽管不能在回调反应器中使用由entlast和entget等函数获取VLA对象,但可以用vlax-ename-vla-object函数将ename对象转换成VLA对象。(2)如果对象已被包括在对象反应器的所有者列表之中,那么就不能在回调函数中修改该对象。如果这样做,将会导致一个出错消息,并使AutoCAD崩溃。下面是实现对象反应器功能的实例:,(1)加载例11-3所示程序段【例11-3】生成一个圆的VLA对象。(setq myCircle(progn(setq ctrPt(getpoint n输入圆心:)radius(distance ctrPt(getpoint ctrpt n输入半径:)(vla-addCircle(vla-get-ModelSpace;将圆加入到图形模型空间(vla-get-ActiveDocument(vlax-get-acad-object)(vlax-3d-point ctrPt)radius)该代码使用vla-addCircle画一个圆,将返回值赋给变量myCircle。该返回值是VLA对象,包含指向所画圆对象的指针。,(2)加载例11-1 所示回调函数print-radius。(3)定义对象反应器(setq circleReactor(vlr-object-reactor(list myCircle)Circle Reactor(:vlr-modified.print-radius)(4)在AutoCAD图形窗口,选取该圆并修改其大小,print-radius 函数将在AutoCAD命令窗口显示一个消息。例如,如果用夹点或STRETCH命令改变了该圆的大小,将在命令提示区显示以下信息:*STRETCH*Specify stretch point or Base point/Copy/Undo/eXit:这个圆的半径是:190.0 如果用夹点或STRETCH命令改变其他圆时的大小,将没有该提示信息中的“这个圆的半径是:”,这是因为在其他的圆上没有链接circleReactor反应器。,11.3.2 创建其它反应器 其它反应器不需要链接AutoCAD图元,所以在定义时,只需要两个参数。创建其它反应器通过函数vlr-reactor,该函数的调用格式如下:(vlr-reactor data callbacks)参数data为任意要与反应器对象关联的数据,如果没有数据则该项为nil。参数callbacks为点对表,指明事件和与该事件相关联的回调函数,点对表的格式如下:(event-name.callback_function)例如,下列代码定义了一个DWG编辑器反应器。当用户发出Save命令时,该反应器将激活saveDrawingInfo函数。(vlr-dwg-Reactor nil(:vlr-saveComplete.saveDrawingInfo)在该例中,第一个参数为nil是因为没有与反应器相关联的数据;第二个参数是点对表,指明:vlr-saveComplete事件与saveDrawingInfo回调函数相关联。当:vlr-saveComplete事件发生时,AutoCAD传递给回调函数一个图形文件名字的字符串。,每个点对表都指定了反应器要通报的事件,以及该事件发生时要调用的回调函数。在本例中,只指定了一个事件:vlr-saveComplete。只要用户发出命令,不管是从AutoCAD命令行、菜单、工具栏或AutoLISP程序,都会通知编辑器反应器。所以,该DWG反应器的回调函数需要明确它应对什么事件作出响应。在本例中,回调函数saveDrawingInfo只是检查Save命令。下面是实现DWG反应器功能的实例:(1)加载例11-2所定义的回调函数saveDrawingInfo。(2)定义DWG反应器(vlr-dwg-Reactor nil(:vlr-saveComplete.saveDrawingInfo)(3)在AutoCAD图形窗口点取存盘的图标或调用存图的命令。当完成存图工作时将会弹出图11-1所示的AutoCAD Message对话框。说明该实例成功。,图11-1AutoCAD的Message对话框,11.3.3 将数据附着到反应器对象 利用创建反应器函数的参数data可以为反应器指定与其关联的数据,如果该项为nil,表示不需要为反应器指定与其关联的数据。一个对象可能链接多个反应器,如果它们的参数data都为nil,应用程序将无法区分它们。在这种情况下就应该为反应器指定文本字符串或应用程序能识别的其它数据。例如,前面创建对象反应器circleReactor的实例中,字符串“CircleReactor”就是与反应器circleReactor相关联的数据。11.4 查询、修改和控制反应器的状态11.4.1 查询反应器 有多种不同的方法来获取反应器的信息。可以使用标准的VLISP数据查看工具查看反应器的信息,也可以用有关反应器的AutoLISP函数。,1.了解图形中有关反应器的总体情况 通过vlr-reactors函数可以了解当前图形中总共用到了哪些反应器或有哪些指定类型的反应器。vlr-reactors函数的调用格式如下:(vlr-reactors reactor-type.)参数reactor-type为反应器类型的标识符。如果指定了reactor-type参数,该函数返回由指定类型反应器组成的表。如果省略参数reactor-type,该函数返回所有当前图形所有的反应器。以下表达式列出图形中的所有反应器:(vlr-reactors);返回(:VLR-Object-Reactor#)(:VLR-Editor-Reactor#),有一个对象反应器和一个编辑器反应器。,以下表达式列出所有的对象反应器:(vlr-reactors:vlr-object-reactor);返回(:VLR-Object-Reactor#),有一个对象反应器以下表达式列出所有数据库反应器:(vlr-reactors:vlr-acdb-reactor);返回nil,没有数据库反应器以下表达式列出所有DWG反应器:(vlr-reactors:vlr-dwg-reactor);返回(:VLR-DWG-Reactor#),有一个DWG反应器,有两个指向该DWG反应器的指针。,2.用VLISP的检验工具检查反应器 可以使用VLISP的检验工具检查反应器。在VLISP编辑器窗口选择circleReactor,单击按钮,将弹出图11-2所示检验窗口,该窗口显示以下信息:,图11-2有关反应器的检验窗口,l 反应器的类型标识符,如VLR-Object-Reactorl 该反应器的所有者,如l 事件和与之相关联的回调函数,如:VLR-modified PRINT-RADIUSl 该反应器是否是活动的:如果是活动的,added-p 为 T,否则它为 nill 附着到反应器上的用户数据,如“Circle Reactor”l 反应器的文档范围:如active-document-onlyl 该反应器所在文挡:如双击以 Owners 开头的条目,可查看反应器所有者的列表。,3.用函数调用、查询反应器VLISP还提供了可在应用程序或控制台提示处查看反应器定义的函数:(1)vlr-type函数返回指定反应器的类型,例如:(vlr-type circleReactor);返回:VLR-Object-Reactor(对象反应器)(2)vlr-current-reaction-name 函数返回当前反应器触发回调函数的事件名称。例如:(vlr-current-reaction-name);返回nil(3)vlr-data 返回附着到反应器的特定应用程序数据,可用该数据区分链接在同一个对象上的多个反应器。例如:(vlr-data circleReactor);返回 Circle Reactor“(4)vlr-owners函数返回向某对象反应器发出通报的AutoCAD图形中的对象(反应器所有者)列表,下述函数调用将列出 circleReactor 的所有者:(vlr-owners circleReactor);返回(#)(5)vlr-reactions函数返回指定反应器的回调条件回调函数列表,下例将返回 circleReactor 的相关信息。例如:(vlr-reactions circleReactor);返回(:VLR-modified.PRINT-RADIUS),11.4.2 修改反应器1 添加或替换反应器的回调函数 通过函数vlr-reaction-set可以添加或替换反应器中的一个回调函数。该函数的调用格式如下:(vlr-reaction-set reactor event function)参数reactor为反应器 对象。event为符号,表示该反应器类型可用的事件之一。Function为要添加或替换的AutoLISP函数名。返回值未确定。例如,下面的命令使反应器circleReactor在修改对象时调用print-area函数:(vlr-reaction-set circleReactor:vlr-modified print-area);返回PRINT-AREA,2.修改与反应器相关联的数据 通过函数vlr-data-set可以修改与反应器相关联的数据。该函数的调用格式如下:(vlr-data-set obj data)参数obj为反应器对象,表示要修改数据的反应器对象。data为新数据。返回值为参数data。例如,查看附着到反应器circleReactor的数据值:(vlr-data circleReactor)返回Circle Reactor 用字符串Circle Area Reactor替换反应器circleReactor的原有数据Circle Reactor:(vlr-data-set circleReactor Circle Area Reactor);返回Circle Area Reactor 验证是否有了改变:(vlr-data circleReactor);返回Circle Area Reactor 注意,应小心使用vlr-data-set函数,以免构成循环结构。,3.将一个数据库对象添加到反应器的所有者列表内 通过函数vlr-owner-add可以将一个数据库对象添加到指定反应器的所有者列表内。该函数的调用格式如下:(vlr-owner-add reactor owner)参数reactor为反应器对象。owner为要添加到反应器所有者列表中的VLA对象。返回值为已添加了反应器的VLA对象。例如,在下例中,名为archie的圆弧对象被添加到反应器circleReactor的所有者列表中:(vlr-owner-add circleReactor archie);返回#可通过检验该反应器来验证这点:更新反应器 circleReactor 的检验窗口,用鼠标双击检验窗口的Owners开头的条目,将弹出图113所示的反应器所有者检验窗口。,图113反应器所有者的检验窗口,4.从反应器所有者列表中删除某所有者对象 通过函数vlr-owner-remove可以从反应器所有者列表中删除某所有者对象。该函数的调用格式如下:(vlr-owner-remove reactor owner)参数reactor为反应器 对象。owner为要从反应器所有者列表中删除的VLA对象。返回值为被删除的VLA对象。例如:(vlr-owner-remove circleReactor archie);返回#,11.4.3 控制反应器的状态1.判断反应器是否是活动的 通过函数vlr-added-p可以判断反应器是否是活动的。vlr-added-p函数的调用格式如下:(vlr-added-p obj)参数obj为反应器对象,表示要测试的反应器。如果反应器是活动的(已在 AutoCAD 中注册),返回T,如果该反应器失效,则返回nil。例如:(vlr-added-p circleReactor);返回T,表示该反应器是活动的,2.使反应器失效 通过函数vlr-remove可以使指定的反应器失效。vlr-remove函数的调用格式如下:(vlr-remove obj)参数obj为反应器对象。如果成功,返回反应器对象,否则,返回nil。例如,使反应器circleReactor失效:(vlr-remove circleReactor);返回#注意,失效的反应器,并没有从内存中被删除,该反应器仍然存在。,2.恢复失效的反应器 通过函数vlr-add可以恢复指定的失效反应器,使之成为活动的(在AutoCAD中注册)。vlr-add函数的调用格式如下:(vlr-add obj)参数obj为反应器对象,表示要恢复的失效反应器。如果成功,返回反应器对象,否则,返回nil。例如,恢复失效的circleReactor反应器:(vlr-add circleReactor);返回#通过函数vlr-remove-all可以使图形中所有的反应器失效。vlr-remove-all函数的调用格式如下:(vlr-remove-all reactor-type),可选参数reactor-type为反应器类型的标识符,如果未指定reactor-type,该函数禁用图形中所有的反应器。返回为包含若干个子表的表,每个子表的第一个元素表示反应器的类型,后续元素表示禁用的反应器对象。如果没有活动的反应器,该函数返回nil。例如,下面的函数调用将禁用所有编辑器反应器:(vlr-remove-all:vlr-editor-reactor)返回(:VLR-Editor-Reactor#)下面的调用函数将禁用所有反应器:(vlr-remove-all)返回(:VLR-Object-Reactor#)(:VLR-Editor-Reactor#),11.5 临时反应器和永久反应器 反应器可以是临时的,也可以是永久的。二者的区别是:下一次打开该图形时,临时反应器将丢失,永久反应器则仍然存在。前者是反应器的默认模式。1.将临时反应器变成永久反应器 通过函数vlr-pers可以将临时反应器变成永久反应器。函数vlr-pers的调用格式如下:(vlr-pers obj)参数obj为反应器对象。如果成功则返回指定的反应器对象,否则返回 nil。例如:(vlr-pers circleReactor);返回#,2.将永久反应器改变为临时反应器 通过函数vlr-pers-release可以将永久反应器改变为临时反应器。函数vlr-pers的调用格式如下:(vlr-pers-release obj)参数obj为反应器对象。如果成功则返回反应器对象,否则返回 nil。(vlr-pers-release circleReactor);返回#3.判断反应器是否是永久反应器 通过函数vlr-pers-p可以判断反应器是否是永久反应器。函数vlr-pers-p的调用格式如下:(vlr-pers-p obj)参数obj为反应器对象。如果指定反应器是永久反应器,则返回指定的反应器对象,否则返回nil。例如:(vlr-pers-p circleReactor);返回#,4.列出当前图形文档中的永久反应器 通过函数vlr-pers-list可以列出当前图形文档中的永久反应器。函数vlr-pers-list的调用格式如下:(vlr-pers-list reactor-type)参数reactor-type为要列出的反应器对象。如果未指定reactorr-type,该函数列出所有永久反应器。返回值为由反应器对象组成的表。例如:(vlr-pers-list);返回(#(#),打开含有永久反应器的图形时的注意事项 反应器只是链接事件和回调函数的一种工具,回调函数本身不是反应器的一部分,它一般也不是图形的一部分。只有AutoCAD中加载了相关联的回调函数时,图形中保存的反应才有实际作用。如果将反应器和回调函数定义在独立名称空VLX中,则在打开图形时会自动加载回调函数。如果打开的图形包括VLISP反应器信息,但没有加载相关回调函数,AutoCAD会显示一个错误信息。可用函数vlr-pers-list返回图形文档中所有永久反应器组成的表。,11.6 反应器的使用规则 由于将来可能修改反应器的内部实现机制,使用反应器时请尽量遵守下述规则,如果不遵守这些规则,可能会导致应用程序出现不可预料的结果。(1)不要依赖于反应器通报的顺序 除了少数特例之外,建议不要依赖于反应器通报的顺序。例如,OPEN命令将触发 BeginCommand、BeginOpen、EndOpen 和 EndCommand事件。然而,它们发出的顺序可能不是这样的。可以依赖的顺序只有Begin事件是在相应End事件之前。例如commandWillStart()总是在commandEnded()之前发生,而beginInsert()总是在endInsert()之前发生。因为将来可能引入新的事件通报,可能会重新排列现有通报顺序,所以依赖于更复杂的顺序,可能会给您的应用程序带来问题。,(2)不要依赖于通报间函数调用的顺序 在通报之间函数调用的顺序也是不能保证的。例如,当收到对象A 的通报:vlr-erased 时,它仅表示对象A被删除,如果在收到对象A的通报:vlr-erased 之后收到了对象B的通报:vlr-erased,这只是表示对象A和B都已被删除。并不能保证B是在A后面被删除。如果应用程序依赖于这个层次的关系,那么应用程序在后续版本的AutoCAD中很可能会崩溃。所以不要依赖于这些顺序,而应该依赖于用反应器来指示系统的状态。(3)不要在反应器回调函数中使用任何需要和用户交互的函数 在反应器回调函数中试图调用交互函数会导致严重问题,因为在事件发生时,AutoCAD可能仍在处理某命令。所以要避免使用要求用户输入的函数,如getpoint、entsel和getkword等,也不要使用选择集操作函数和command函数。,(4)在事件处理函数中不要加载对话框 对话框和用户交互函数一样,也会影响AutoCAD的当前操作。但是,消息对话框和警告对话框可认为是非交互的,所以可以使用它们。(5)不要更新引发事件的对象 引起对象触发回调函数的事件可能仍在处理之中,当调用回调函数时AutoCAD可能仍在使用该对象。所以,在回调函数中不要试图更新这样的对象。然而,可以从触发事件的对象中读取信息。例如,假设有一块用砖填充的地板,而且将反应器链接到地板边界上。如果修改地板的尺寸,反应器回调函数将自动添加或删除砖以填充新的地板面积。通过函数能够获取边界的新面积,但不能去修改边界本身。,(6)不要在回调函数中执行能触发相同事件的操作 如果在反应器回调函数中执行的某操作过程中触发了同样的事件,将会陷入一个无限循环。例如,如果在BeginOpen事件的回调函数中试图打开一个图形,AutoCAD将持续打开更多的图形,直到打开的图形数目达到上限,无法再打开图形为止。(7)能在发生同一事件时调用多个回调函数 在设置反应器以前要确认当前没有设置该反应器,否则可能在发生同一事件时调用多个回调函数。(8)显示有模对话框时,不会发生任何事件 所谓有模对话框,是指操作其它窗口之前必须关闭的话框时。显示这样的对话框时,不会发生任何事件。,11.7定义反应器实例1.定义将对象反应器链接到指定直线的命令。要求:当直线被修改时,弹出显示该直线长度的信息对话框。很明显,反应器的链接对象就是指定的直线。触发事件是直线被修改,从表11-4可以查找出图形对象被修改的事件是:vlr-modified。回调函数的功能是调用信息对话框显示被选直线长度。程序的代码如下:【例11-4】定义将对象反应器链接到指定直线的命令。(vl-load-com)(defun c:rct-line(/el rlt vrl)(setq el(car(entsel n选择一条链接反应器的直线:)(setq rlt(list(vlax-ename-vla-object el);将图元名转换为VLA对象,;创建对象反应器,回调事件是图元被修改,回调函数是show-l(setq vrl(vlr-pers(vlr-object-reactor rlt nil(:vlr-modified.show-l)(princ);定义回调函数(defun show-l(notifier-object reactor-object parameter-list/l)(setq l(vla-get-length notifier-object);将被选直线的长度赋给变量l(setq l(rtos l 2 4);将数值转换为字符串(alert(strcat 直线的长度是:l);调用信息对话框),加载以上程序,在Command:提示下输入rct-line命令,用鼠标指定一条直线,该反应器就会链接到指定的直线上。修改这条直线时,就会出现图114所示显示有该直线当前长度信息的对话框。,图114显示直线当