Tom Berger
;;;; here it goes:
;; simple reactor sample
;; You should also program the "erasedfunction" that
;; should remove the reactor, whenever one of the
;; objects has been deleted
;;
;; now, we first activate the COM environment:
(vl-load-com)
(defun c:rstart ()
(command "._zoom" '(0 0) '(20 15))
;; I draw a circle and a text entity
;; you may do this also manually
(if (entmake '((0 . "CIRCLE")
(100 . "AcDbEntity")
(67 . 0)
(410 . "Model")
(8 . "0")
(100 . "AcDbCircle")
(10 5.0 5.0 0.0)
(40 . 2.5)
(210 0.0 0.0 1.0)
)
)
(setq circle (entlast))
)
(if (entmake '((0 . "TEXT")
(100 . "AcDbEntity")
(67 . 0)
(410 . "Model")
(8 . "0")
(100 . "AcDbText")
(10 7.0 7.0 0.0)
(40 . 1.0)
(1 . "10")
(50 . 0.0)
(41 . 1.0)
(51 . 0.0)
(7 . "Standard")
(71 . 0)
(72 . 0)
(11 0.0 0.0 0.0)
(210 0.0 0.0 0.0)
(100 . "AcDbText")
(73 . 0)
)
)
(setq text (entlast))
)
(if (and circle text)
(progn
;; now we create the reactor for the circle:
(create-objectreactor
;; the owner list
(list (vlax-ename->vla-object circle))
;; the owner list
;; the reactor data ("MYAPPNAME" ist just to recognize my reactor)
;; the text entity is stored within the reactor data
(list "MYAPPNAME" (vlax-ename->vla-object text))
)
;; now we create the reactor for the text entity:
(create-objectreactor
;; the owner list
(list (vlax-ename->vla-object text))
;; the owner list
;; the reactor data ("MYAPPNAME" ist just to recognize my reactor)
;; the circle entity is stored within the reactor data
(list "MYAPPNAME" (vlax-ename->vla-object circle))
)
)
)
(princ "\nThe circle and the text entity could have also been drawn by
you.")
(princ "\nNow, whenever you modify the circle's radius
(pickstretch),")
(princ "\nthe text shows the actual radius.")
(princ "\nAnd, of course, whenever you modify the content of the text
entity")
(princ "\nto another value, the circle immediately modifies it's
radius.")
(prin1)
)
(defun create-objectreactor (ownerobjects data / myreactor)
(setq myreactor
(VLR-OBJECT-Reactor
ownerobjects
data
'(
(:vlr-modified . updatefunction)
;; (:vlr-erased . erasedfunction)
)
)
)
;; (vlr-pers reactor)
)
;;; this is the function that is executed when
;;; the reactor fires on the event ":vlr-modified"
(defun updatefunction (firingobject firedreactor event
/ data firingentlist
radius text dependendobject
dependingentlist
)
;; in this sample: the dependend object is stored in the reactor data:
(setq data (vlr-data firedreactor))
;; the firing object's entget list is:
(setq firingentlist (entget (vlax-vla-object->ename firingobject)))
;;; we read the radius of the circle or the value of the text entity:
(cond
((= "CIRCLE" (cdr (assoc 0 firingentlist)))
(setq radius (cdr (assoc 40 firingentlist)))
)
((= "TEXT" (cdr (assoc 0 firingentlist)))
(setq text (cdr (assoc 1 firingentlist)))
;; is the string a number?
(if (numberp (read text))
(setq radius (float (read text)))
)
)
)
;; now we check for the radius - if no radius
;; is set we don't have to do anything -
;; and we check the dependend object
;; I stored this inside the reactor data
;; and to be on the safe side I added my
;; unique Appname as the first element of the
;; reactor data
(if (and radius
(= "MYAPPNAME" (car data))
)
(progn
(setq dependendobject (cadr data))
;; now I would have to check wether the
;; depended object is still available
;; but this is just a sample ...
;; the enity list of the dependend object is
(setq dependingentlist
(entget (vlax-vla-object->ename dependendobject)
)
)
;; and depending of the type of object we modify it
(cond
((= "CIRCLE" (cdr (assoc 0 dependingentlist)))
(entmod (subst (cons 40 radius)
(assoc 40 dependingentlist)
dependingentlist
)
)
)
((= "TEXT" (cdr (assoc 0 dependingentlist)))
(entmod (subst (cons 1 (rtos radius 2 2))
(assoc 1 dependingentlist)
dependingentlist
)
)
)
)
(entupd (cdr (assoc -1 dependingentlist)))
)
)
)
(princ "\nEnter \"RSTART\" at the command prompt ...")
(prin1)
You cannot call AutoCAD commands using the command function. Also, to access
drawing objects, you must use ActiveX functions; entget and entmod are not
allowed inside callback functions, among other things....
Regards,
-Luis Esquivel
It does work as it is written, at least on my machine. Have you tried it?
Don
"Luis Esquivel" <arch...@onebox.com> wrote in message
news:34958AE25FF5B330...@in.WebX.maYIadrTaRb...
I'm not refering to the COMMAND function, he is using ENTMOD
entmod (subst (cons 40 radius)
(assoc 40 dependingentlist)
dependingentlist
)
)
)
((= "TEXT" (cdr (assoc 0 dependingentlist)))
(entmod (subst (cons 1 (rtos radius 2 2))
> It does work as it is written, at least on my machine. Have you tried it?
I have not, and I know that must work just by reading the code, I have seen
professional programmers use the same secuence of code like Bill Kramer in
one of the early examples for reactors, some years ago.
My only point is about following the rules.
The End
There is no command inside a reactor function.
> Also, to access
> drawing objects, you must use ActiveX functions; entget and entmod are not
> allowed inside callback functions, among other things....
Where did you read this? I can't find a statement like that, and I use
entmod and entget since lon in my applications. Of course, however, you
are not allowed to modify the object which called the reactor. In my
sample it is another object which is modified.
Tom Berger
--
ArchTools: Software-Werkzeuge für die Architektur
ArchDIM - architekturgerechte Bemaßung für AutoCAD (TM)
ArchAREA - Flächenermittlung und Raumbuch nach DIN 277
Info und Demo unter http://www.archtools.de
If you open the Help file, go to Visual Lisp developer's Guide -> Chapter 7
Advanced Topics ->Attaching reactors to AutoCAD drawings -> Reactors Use
Guidelines
I'm using A2K
Regards,
-Luis
Here is:
When using reactors, try to adhere to the following guidelines. Reactors
that violate these guidelines can result in unpredictable results for your
application if the internal implementation of reactors changes.
Do not rely on the sequence of reactor notifications.
It is recommended that, with a few exceptions, you do not rely on the
sequence of reactor notifications. For example, an OPEN command triggers
BeginCommand, BeginOpen, EndOpen, and EndCommand events. However, they may
not occur in that order. The only event sequence you can safely rely on is
that a Begin event will occur before the corresponding End event. For
example, commandWillStart() always occurs before commandEnded(), and
beginInsert() always occurs before endInsert(). Relying on more complex
sequences may result in problems for your application if the sequence is
changed as a result of new notifications being introduced in the future and
existing ones being rearranged.
Do not rely on the sequence of function calls between notifications.
It is not guaranteed that certain functions will be called between certain
notifications. For example, when you receive :vlr-erased notification on
object A, all it means is that object A is erased. If you receive
:vlr-erased notification on A followed by a :vlr-erased notification on B,
all it means is that both objects A and B are erased; it does not ensure
that B was erased after A. If you tie your application to this level of
detail, there is a very high probability of your application breaking in
future releases. Instead of relying on sequences, rely on reactors to
indicate the state of the system.
Do not use any interactive functions in your reactor callback function (for
example, do not use getPoint, entsel).
Attempting to execute interactive functions from within a reactor callback
function can cause serious problems, as AutoCAD may still be processing a
command at the time the event is triggered. Therefore, avoid the use of
input-acquisition methods such as getPoint, entsel, and getkword, as well as
selection set operations and the command function.
Do not launch a dialog box from within an event handler.
Dialog boxes are considered interactive functions and can interfere with the
current operation of AutoCAD. However, message boxes and alert boxes are not
considered interactive and can be issued safely.
Do not update the object that issued the event notification.
The event causing an object to trigger a callback function may still be in
progress and the object still in use by AutoCAD when the callback function
is invoked. Therefore, do not attempt to update an object from a callback
function for the same object. You can, however, safely read information from
the object triggering an event. For example, suppose you have a floor filled
with tiles and you attach a reactor to the border of the floor. If you
change the size of the floor, the reactor callback function will
automatically add or subtract tiles to fill the new area. The function will
be able to read the new area of the border, but it cannot attempt any
changes on the border itself.
Do not perform any action from a callback function that will trigger the
same event.
If you perform an action in your reactor callback function that triggers the
same event, you will create an infinite loop. For example, if you attempt to
open a drawing from within a BeginOpen event, AutoCAD will simply continue
to open more drawings until the maximum number of open drawings is reached.
Verify that a reactor is not already set before setting it, or you may end
up with multiple callbacks on the same event.
Remember that no events will be fired while AutoCAD is displaying a modal
dialog.
> My only point is about following the rules.
Are there new rules for reactors in A2ki and A2002? I am still using A2K
and the reactor guidelines in A2K don't forbid the usage of entmod and
entget. However - I do not modify the object that is calling the reactor
which would definitely not be according the guidelines.
> Here is:
>
> When using reactors, try to adhere to the following guidelines. ...
And where do you see that entget and entmod is not allowed?
Tom,
By reading the help file:
entget and entmod are not allowed inside callback functions,...
Well I don't know if there are new rules, inside a2ki-a2002, I not using
them, but after making several examples and commands with reactors, I simple
follow and avoid the use of entget, entmod, setvar, getvar, command, even if
I not doing any modification.
Tom, what happens is that I'm preparing some examples to some of my friends
that are learning the use of reactors in visual lisp (I'm teaching them
Visual Lisp/Activex), and I'm trying to follow the guidelines, if you think
or by experience that what you are doing works, please ignore my comments.
Good luck,
-Luis Esquivel
www.arqcom.com.mx
> Tom, what happens is that I'm preparing some examples to some of my friends
> that are learning the use of reactors in visual lisp (I'm teaching them
> Visual Lisp/Activex), and I'm trying to follow the guidelines, if you think
> or by experience that what you are doing works, please ignore my comments.
No, I am not offended! If there is a rule not to use entget or entmod in
reactor functions then I should modify my code. But even in the snipped
part of the guidelines which you posted here I can't find anything about
entmod end entget.
Indeed I believe that entget is absolutely non-critical in reactor
functions because it is just a function to retrieve information from the
database. Entmod may be different, and for sure the object which is
calling the reactor is not to be modified by the reactor function. I use
entmod to modify another object which has nothing to do with the
reactor.
But indeed I use a different approach in my applications which would
have ben too difficult for this small sample. My
object-reactor-functions do nothing else then collect the object-names
in a global variable. An editor reactor is fired on command-ended. The
editor-reactor's callback function looks for the entities in the global
variable and modifies them according my app's need (using entmod, of
course).
Attaching Reactors to AutoCAD Drawings
Defining Callback Functions
To add reactor functionality to your application, you first need to write a
callback function that performs the tasks needed at the time of the reactor
event. After you define a callback function, you link the function to an
event by creating a reactor object.
A callback function is a regular AutoLISP function, which you define using
defun. However, there are some restrictions on what you can do in a callback
function. You cannot call AutoCAD commands using the command function. Also,
to access drawing objects, you must use ActiveX functions; entget and entmod
are not allowed inside callback functions. See "Reactor Use Guidelines" for
more information.
Callback functions for all reactors, other than Object reactors, must be
defined to accept two arguments:
The first argument identifies the Reactor object that called the function.
The second argument is a list of parameters set by AutoCAD.
The following example shows a function named saveDrawingInfo, which displays
file path and size information. This function will be attached to a DWG
Editor reactor that will fire when an AutoCAD drawing is saved.
(defun saveDrawingInfo (calling-reactor commandInfo / dwgname filesize)
(vl-load-com)
(setq dwgname (cadr commandInfo)
filesize (vl-file-size dwgname)
)
(alert (strcat "The file size of " dwgname " is "
(itoa filesize) " bytes."
)
)
(princ)
)
In this example, the calling-reactor variable identifies the reactor that
invoked the function. The function retrieves the drawing name from the
commandInfo parameter, then uses the vl-file-size function to retrieve the
size of the drawing. Finally, the function displays the information in an
alert box in the AutoCAD window.
The parameters passed to a callback function depend on the type of event
associated with the function. For example, saveDrawingInfo will be
associated with a saveComplete event. This event indicates that a Save
command has been completed. For saveComplete events, AutoCAD passes the
callback function a string containing the name of the file the drawing was
saved in. On the other hand, a callback function that reacts to changes to
system variables (sysVarChanged event) receives a parameter list containing
the name of a system variable (a string) and a flag indicating if the change
was successful. You can find a list of events for each reactor type, and the
parameters associated with each event, in the AutoLISP Reference. The events
are listed under the description of the functions used to define each type
of reactor.
AutoCAD comes with two predefined callback functions. You can use these
functions when testing your reactors:
vlr-beep-reaction is a simple function that beeps your PC.
vlr-trace-reaction prints a list of arguments to the VLISP Trace window
each time a reactor fires this callback function.
Topics in this section:
<> Defining Object Reactor Callback Functions
"Tom Berger" <ber...@archtools.de> wrote in message
news:3B659FE7...@archtools.de...
> to access drawing objects, you must use ActiveX functions; entget and entmod
> are not allowed inside callback functions. See "Reactor Use Guidelines" for
> more information.
Ah, here it is - it's not in my (German version) of A2K. However, the
usage of entget should be non-critical as it just retrieves information
from the database. As I didn't get any errors using entmod I think that
it is meant like "not to use entmod to modify the object which called
the reactor".
I'll keep as it is, but thank's for the info!