AfraLISP - Learn AutoLISP for AutoCAD productivity

Reactors - Part 1

by Kenny Ramage

What are Reactors?

"What the heck is a reactor?" I asked myself exactly the same question when I first came across the phrase. "It must be another name for an Event", I said to myself. I was wrong, again!

A reactor is an Object you attach to AutoCAD Objects to have AutoCAD notify your application when a particular event, or events occur. (Remember, that an AutoCAD Object can be an Object within your drawing, the drawing itself, or even AutoCAD, the application - just thought I'd tell you). This is the general procedure :

  • An Event occurs in your drawing.
  • AutoCAD notifies the Reaction associated with that Event.
  • The reaction then notifies your application, known as a callback function, passing to it certain information applicable to the Event in the form of arguments.
  • Your application then does it's thing using the information passed to it from the Reactor.

So, in simple terms, a Reactor is the "link" between the Event and the callback function.

Before we get into looking at the different types of AutoCAD Reactors and Events, let's have a look at a fairly straightforward Reactor to give you an idea of how simple they can be. Before you start though, you must ask yourself two questions :

  1. Before, after or during what Event do you want your function to occur?
  2. What do you want your function to do?

For this example, I will answer both these questions on your behalf.

  1. "I want my function to run every time a drawing Save is completed".
  2. "I want the function to tell me what the name of the drawing is, and how big the drawing is".

O.K. Looking at the Reactor listings, (Refer to Visual Lisp Reference), under the Editor Reactor Types, I find a reactor called vl-dwg-reactor. This reactor, I am led to believe, responds to the "Save Complete" event of a drawing, and returns callback data of a string containing the actual file name used for the save. Hey, this is just what we are looking for. Let's order two to take-away…

Enough of this childish wit! Let's have a look at the reactor definition and syntax first :

vlr-dwg-reactor - Constructs an editor reactor object that notifies of a drawing event.

(vlr-dwg-reactor data callbacks)

Arguments :

data : AutoLisp data to be associated with the reactor object, or nil, if no data

callbacks : A list of pairs of the following form :

   (event-name . callback_function)

where event-name is one of the symbols listed in the "DWG reactor events" table, and callback_function is a symbol representing the function to be called when the event fires. Each callback function will accept two arguments :

reactor_object - the VLR object that called the callback function,
list - a list of extra data elements associated with the particular event.

How does it work?

I don't know about you? But, whew…! Right, let's try and put this into simple English. Let's look at the syntax again :

(vlr-dwg-reactor data callbacks)

The first part vlr-dwg-reactor is easy. This is the name of the reactor type. This name will be sent to your call back function.

The first argument data, is User Application Data. We usually set this to a reactor name of our choosing. This way we can distinguish between reactors if an Objects has multiple reactors attached.

The second argument callbacks is a straightforward list of dotted pairs.

  • The first element of the list is the name of the reactor "event" that will trigger the reactor and then call your callback function.
  • The second element, is the name of your Callback function.

This is what our reactor function will look like :

(vlr-dwg-reactor "Save Complete"  '((:vlr-savecomplete . savedrawinginfo)))

Or, graphically :

Reactor Diagram

Let's have a look at our Reactor Function in action. Copy and Paste this coding into the Visual LISP Editor and save it as SaveDrawingInfo.lsp. Next Load the application, but do not run it.

(vl-load-com)
 
;**************************************************************
 
;setup and intilise the reactor
(vlr-dwg-reactor "Save Complete" '((:vlr-savecomplete . savedrawinginfo)))
 
;**************************************************************
 
(defun saveDrawingInfo (calling-reactor commandInfo / dwgname filesize
                                         reactType reactData reactCall
                                              reactEvent reactCallback)
 
;get the reactor Object
(setq reactInfo calling-reactor
 
      ;get the reactor Type
      reactType (vl-symbol-name (vlr-type reactInfo))
 
      ;get the Application Data
      reactData (vlr-data reactInfo)
 
      ;get the Callback list
      reactCall (car (vlr-reactions reactInfo))
 
      ;extract the Event Reactor
      reactEvent (vl-symbol-name (car reactCall))
 
      ;extract the Callback Function
      reactCallback (vl-symbol-name (cdr reactCall))
 
);setq
 
;get the Drawing Name
(setq dwgname (cadr commandInfo)
 
     ;extract the filesize
     filesize (vl-file-size dwgname)
      
);setq
 
;display the Drawing Name and Size
(alert (strcat "The file size of " dwgname " is "
	       
(itoa filesize) " bytes."))
 
;Display the Reactor Information
(alert
 
  (strcat
    "A " "\"" reactType "\"" " named " "\"" reactData "\"" "\n"
    "was triggered by a " "\"" reactEvent "\"" " event call." "\n"
    "Callback Data was passed to the" "\n"
    "\"" reactCallback "\"" " call back function."))
 
(princ)
 
);defun
 
;********************************************************
 
(princ)
 
;********************************************************

Once the application is loaded, return to AutoCAD and save the drawing. This dialog will appear :

AutoCAD Message

Followed by this dialog :

AutoCAD Message

Do you notice the calling-reactor and commandInfo argument declarations? This information, the Reactor Object Name and the Event Parameter Information is passed to our Callback Function from the Reactor. Clever hey?

In Part 2, we'll have a look at some Drawing Reactors.