Entity Level Reactors in VBA28 Feb, 2001 By: Bill Kramer
At last November's Autodesk University in Las Vegas I taught a class during which we discussed reactors in general terms and showed a simple example. In that class I said that one could write a program that uses a reactor to prevent the deletion of an important entity object by duplicating the entity object before it gets erased. Since then I have had several students contact me asking how to accomplish this task. So here is the solution for those who asked as well as for those who wanted to ask, but didn't. It does provide a great example of how reactors can be exploited.
First, a little background. Reactors are functions we write that run in response to something happening in the computer system. Dialog boxes and many other interfaces are full of reactor type functions. Another way of looking at reactors is as functions you write that may or may not be run during the life of an application. They only run when something causes them to run. That is, a reactor reacts to some special circumstance. In the case of a dialog box, a reactor is "attached" to a control such as a button. When the button is pressed, the reactor runs and does something. It may change the way other things appear on the screen or it may cause the dialog box to be interrupted with another dialog box or interactive process. The user may run the application many times before ever hitting that particular button. But if the button exists, then a reactor function must exist for the application to be considered complete.
In terms of AutoCAD, reactors refer to the set of optional functions that run when events occur such as adding a new item to the drawing database, starting a command, ending a command and so forth. The functions that are attached to dialog box components are referred to as callback functions and not considered the same as reactors.Reactor Categories
Reactors fall into several categories. For example, editor reactors run when something happens relative to the editor. Editor reactors include command start and stop notification and other events related to AutoCAD's editor system. Another reactor group is the database reactor set that can be programmed to run when the database is changed. And somewhat related to database reactors is the entity object reactor. There are other reactors exposed in AutoCAD for programmers, but most applications work fine with the database and object-level reactors.
The full suite of reactors is available in only the C++ programming library called ObjectARX. But some have been exposed to the ActiveX interface used by VBA. Note that if you plan to make extensive use of reactors of any kind in your programming work, you should seriously consider the use of ObjectARX as it provides the greatest level of access into the system.
We looked at Reactors for VBA in this column last September. In that column we explored the basics of using reactors. Let's build from that knowledge and go deeper into the reactors.
One of the primary rules of programming reactors is that you cannot veto the event. That is, you cannot prevent or stop whatever event caused the reactor to run. If you are notified that something is being deleted, you cannot stop it from being deleted from the drawing.
So how do you keep an entity object in the drawing at all times? The trick is to duplicate the entity being deleted. From the operator's perspective, the entity did not go away. Internally the entity object was deleted from the drawing. We just replaced it with another one of the same type, at the same location and with the same basic properties. But operators will believe the object they have selected for deletion simply will not go away.
When exploring the AutoCAD VBA system, the first reactors you typically look at are the ones that are easiest to reach in the development editor (IDE). That would be the reactor set attached to the document object. Click on the document object in the Projects windows of the VBA IDE. Then display the code window by pressing F7 (function key seven) or selecting the view code icon. At the top of the code window you will find two drop-down lists. The drop-down list on the left side will show General. This is the list of defined objects. Unfurl the list and select AcadDocument instead. The AutoCAD Document (ThisDrawing) is an object. You can provide definitions for the functions that are permanently attached to the document object.
When you select the AcadDocument object, the list on the right side (attached functions) will fill with function names. These are the document and editor-level reactors available to VBA, as listed in Table 1. To use any of these reactors, just select one from the list and then start typing in the code you want to run. You cannot add new reactors to this list but you can add new functions and subroutines for your own purpose.
Let's take a look at the ObjectErased reactor. We want to create the illusion of a preserved entity by generating a duplicate when the object is deleted, so this is a logical place to begin our quest. When you select the ObjectErased reactor, the subroutine code is set up in the editor window. There is one argument to the function--an ObjectID passed as a long integer. This points to the object being deleted, and so it appears that we just need to convert it to an entity object and duplicate it.
But the problem is that object is tagged for deletion, which means that you can no longer access the properties that were once available in the object. And that includes application specific Xdata.
You cannot convert the "tagged for delete" Object ID into an entity object. An error will result if you use the ObjectIdToObject method in the current drawing. AutoCAD will refuse to return an object since the Object ID points to an object that is considered deleted. And since you cannot convert the Object ID into an entity object, you do not have access to any of the data elements in the object.
All this means that the ObjectErased reactor is essentially useless in our quest to create the object that will not go away. The next alternative is to use an entity object level reactor. Entity object reactors are different in that they only run when the attached entity is directly affected. The ObjectErased reactor works with all entity objects in the drawing while the entity object level reactor will only work with that specific entity object.
Public WithEvents myCircle as AcadCircle
In VBA we have access to one entity level reactor that tells us when the entity has been modified. To create an entity level reactor in VBA, start by creating a new class definition. In the VBA IDE insert a new class module into your project. Change the name property to be whatever you want and then define an object as a public AutoCAD object with events. To illustrate, the following line of VBA code will define an AutoCAD Circle object.
Now unfurl the named objects pulldown menu at the top left of the edit window and select the myCircle object. There will be one function in the list called Modified. Select the Modified function to start the coding process. This function has one argument