CP311-4 Visual Lisp
CP311-4 Visual Lisp
CP311-4
Put the power of Visual LISP in your hands to create, compare, and edit drawings; interact
with Excel; access the Windows registry; and work with reactors. This class demonstrates how to use the
active document, other open documents, and documents using ObjectDBX, and how to interact with other
applications. Well discuss tips for using VLIDE (Visual LISP Integrated Development Environment),
demystifying ActiveX documentation, using ObjectDBX, accessing the Windows registry, and putting reactors
to work. Sample programs will be included. Participants should know LISP but need not know Visual LISP
Assume the system will not be loaded before your program loads.
Advice:
Otherwise:
Entmake
DXF Methods
Entget
VLAX-
+
+
+
+
+
+
+
+
+
-
VLA-
SendCommand
Good/Bad
Command
Command ActiveX
Methods Methods
Entmod
A Comparison of LISP
Methodologies. Use Which
One is Best In Context
2
CP-311--4
Syntax coloring:
a. Reserved words: blue
i. Indicate functions protected by Autodesk. Help identify correct
spelling and protect mistaken reassignment as user variables.
b. Parentheses: Red
c. Nothing is worse than misplaced, missing, or extra parentheses.
d. Comments: Grey
i. The editor ignores these but you shouldnt. Be overabundant with
explanations about the intentions of your code.
e. Strings: Magenta
i. A misplaced double quote can really mess up a program. If large parts
of your program are pink, look for the beginning and decide where to
end the string.
f.
Constants: Green
i. The letters I, l, and 1 look alike. The color here makes the choice
obvious.
AutoComplete
a. Type enough of
a built-in function or reserved word and you can
finish by using CTRL+Spacebar.
b. A short list of choices can be selected from pop down list. See video.
3
CP311-4
Appropos
a. Forget exactly how to spell something or need to look it how to use a
function. No worries. Use apropos. Help is a quick jump from there.
Database exploration.
a. View -> Browse
drawing
database
b. This is great for
finding out about
objects. Avoid the need to use:
i. (setq entinfo (entget(car(entsel))(*)))
ii. (setq tblinf (entget (tblobjname layer targetlayer)))
Debugging Tools
a. Ability to partially load.
i. Double-click
click a parenthesis in the code editor and choose load
selection. After looking at the results in the console and inspecting
variable values, load the next expression, etc.
ii. Reveals errors b
by
y showing the intermediate values. Reduces the
need to add debug printing statements to log variable values.
b. Break on error.
i. Dont know where problems lie?
Use this to hold the value of local
variables in a known state and
open the error trace window.
c. Code animation
i. Find out where your code is
spending its time and where
execution stops.
d. Breakpoints:
i. Stop at a predetermined point to learn
the values of your variables at any point.
Code step
step-through can be performed.
4
CP311-4
Object inspector:
a. Beginning with a value or symbol(you can enter an expression like (vlax-get(vlax
acad-object),
object), you can begin exploring any related thing.
Syntax checking
a. Arent sure whether you have localized
your variables? Choose to report
statistics during syntax checking
10
11
Error Trace
a. CTRL+SHFT+R
b. Identify what is broken. See missing variable values NIL ---
12
Developer Help F1
a. This really should be ffirst
irst rather than last since it has continued to be my
most valuable programming resource.
b. In 2008, the search features were mistakenly omitted (bug). To be able to
search, go to the AutoCAD window and choose Help
Help->Developer
>Developer help from
the menu. The search features there are still intact.
c.
Find the object model under the ActiveX and VBA help area. This is most
important for the Vlisp programmer.
5
CP311-4
What is it?
a. A color coded outline block diagram starting from the application level down
to individual objects.
2.
3.
How to get to
it?
a. In Vlide hit
F1.
6
CP311-4
Object: A single indivisible part (Application, Document, Block, Line, Dictionary, Xrecord)
Objects usually belong to collections but they could be properties of Objects or Collections.
Selectionsets: similar to collections but are considered objects. They have slightly
different capabilities and methods. For example, most collections have an add method.
Selectionsets have an additem method. You can still use vlax-for and vlax-map-collection
on them.
Property: a characteristic of an object or collection. Some properties are read-only. A
property and a collection can refer to the same thing. Blocks collection is a property of a
document. So is the layers collection.
Method: an action applied to a collection or object. Some methods are inherited but are
not explicitly stated. To remove an object from a block, you delete the object.
7
CP311-4
Access To
Application
ActiveDocument
Modelspace
Paperspace
Preferences
ActiveSelectionSet
Use
(vlax-get-acad-object)
(vla-get-activedocument (vlax-get-acad-object)))
(vla-get-modelspace(vla-get-activedocument(vlax-get-acad-object)))
(vla-get-paperspace(vla-get-activedocument(vlax-get-acad-object)))
(vla-get-preferences(vlax-get-acad-object))
(vla-get-activeselectionset(vla-get-activedocument(vlax-get-acadobject)))
Description of Action
Processes every object in the collection.
Equivalent to Foreach
Applies the function to every object in the
collection. Equivalent to Mapcar
Allows partial processing of collection until
condition no longer applies
Addressing low-level items like the Modelspace collection by starting from the application
object is tedious. Therefore, it is good practice to save either the active document or the
active Modelspace object and then to reference lower level objects starting from there.
8
CP311-4
Such code may be more readable and easier to test than the more direct:
The direct approach has one advantage: there are no variables stored or named.
n
The
purposes for each argument can be commented instead.
By using separate setq statements, the programmer can individually test and debug the
process.
The following example is a library access function which uses techniques some
ome find
debatable. It can, however speed access and can shorten other functions, improving
readability.
Example:
The library function ThisModelSpace above stores a global variable to make successive
access to the object faster. Caution should always be exercised when usi
using
ng global
variables however, since they are outside the scope of the functions that use them and
since other functions might use the same symbol names for other purposes. For Vlisp, also,
there can be a problem when objects arent released. Generally it is safe to keep the active
document, the application object, and the model and paper space collections as globals.
Never assume lower level objects should be stored since they can change or disappear.
Given a line stored in variable a. Lets say the lline
ine gets erased. An attempt to access
object data from an erased line leads to an error:
(vla-get-startpoint a)
9
CP311-4
The GetCurrentSpace function takes a document object. This makes the function, nondocument specific. This makes it useful for working in other documents. It wont work on
ObjectDBX documents though.
10
CP311-4
To create a Safearray
1.
2.
4.
5
$vlax-vbdouble ; each data type variable is bound to an integer.
5
13
CP311-4
Vlax-Curve Functions
These make some otherwise difficult geometric operations easy.
Vlax-Curve Functions
Function Format
(vlax-curve-getClosestPointTo curve-obj
givenPnt [extend])
(vlax-curvegetClosestPointToProjection curve-obj
givenPnt normal[extend])
(vlax-curve-getDistAtParam curveobjparam)
(vlax-curve-getDistAtPoint curve-obj
point)
(vlax-curve-getEndParam curve-obj)
(vlax-curve-getEndPoint curve-obj)
(vlax-curve-getFirstDeriv curve-obj
param)
(vlax-curve-getParamAtDist curve-obj
dist)
(vlax-curve-getParamAtPoint curve-obj
point)
(vlax-curve-getPointAtDist curveobjdist)
(vlax-curve-getPointAtParam curve-obj
param)
(vlax-curve-getSecondDeriv curve-obj
param)
(vlax-curve-getStartParam curve-obj)
(vlax-curve-getStartPoint curve-obj)
(vlax-curve-isClosed curve-obj)
(vlax-curve-isPeriodic curve-obj)
(vlax-curve-isPlanar curve-obj)
Returns
Closest point on the curve to input point
Closest point (in WCS) on a curve after projecting
the curve onto a plane
Length of the curve's segment from the curve's
beginning to the specified parameter
Length of the curve's segment from the curve's
beginning to the specified parameter
Parameter of the endpoint of the curve
Endpoint (in WCS) of the curve
First derivative (in WCS) of a curve at the specified
location
Parameter of a curve at the specified distance from
the beginning of the curve
Parameter of the curve at the point
Point (in WCS) along a curve at the distance
specified by the user
Point at the specified parameter value along a
curve
Second derivative (in WCS) of a curve at the
specified location
Start parameter on the curve
Start point (in WCS) of the curve
Is the start point is the same as the endpoint?
(T, nil)
Curve has infinite range in both directions and
there is a period value dT, such that a point on
the curve at (u + dT) = point on curve (u), for
any parameter u? T or nil
Can a plane that contains the curve? T or nil
Curve parameters should not be interpreted as having a meaning apart from the vlax-curve
functions. Autodesks commands generate curve objects that have predictable parameters.
After editing, though, the parameters meaning may be unclear. Do not assume that a
parameter means anything.
14
CP311-4
This example will draw a radius line from the picked point:
15
CP311-4
ObjectDBX
What is ObjectDBX?
An ActiveX service to access and change the contents of AutoCAD drawing files directly
without opening them in the AutoCAD editor. Many built
built-in
in type library wrapper functions
(vla-xxx)
xxx) will work with an ObjectDBX document ((though
though not officially supported).
How is it accessed?
16
CP311-4
3. Object selection doesnt work. Forget about selection sets. This means you must process
entire collections filtering by using object properties.
4. Entity access functions dont work.
a. Dont try to use entget, vlax-vla-object->ename, entmod, ssget, etc.
17
CP311-4
CP311-4
3)use copyobjects to transfer the block definition, 4) give block references that have the
temporary name the new name, 5)delete
the temporary block, and 5) close the
source drawing. Safe-item
item allows the
item method to be used where there is a
possibility that the reference wont exist.
RemapInsertions iterates through the
entire block collection replacing every
reference to the temporary block with the
new block. Notice the nested vlax-for
statements. This allows every object in
every block to be checked and replaced.
Another wrapper, probably unnecessary
is blocks which obtains the block
collection. GetBlockFrom branches
depending on whether the source block
exists in the activedocument.
ivedocument. By
temporarily renaming the existing block
definition, it allows the process of
replacement to preserve dynamic block
information from the source blocks by
copying the definitions whole. By using
vlax-invoke,
invoke, the list of objects to be
copied can be ordinary rather than a
Safearray.
GetBlockFrom is just a start.
Improvements could include working with
a list of block definitions from the same
source drawing, cleaning up attributes,
and preserving dynamic block properties.
19
CP311-4
VLR-Reactors - An Introduction
Detour Ahead Are you sure reactors are your best route?
Our daily commute is sometimes blocked by traffic snarls. Just so, our programming goals have
destinations that must be arrived at on-time and without accidents. Reactors give some choices
but AutoCAD has given us some awfully good toll roads to compete with them.
Destinations
Automatic layering
Custom objects
Alternatives To Reactors
Palettes, Design Center, CUI, Toolbar Macros,
Command Redefinition.
Dynamic Blocks
Fields
Annotation Scaling
Annotation Features
Automatic Saving
savetime
Groups
Scheduling
Layer Standards
Lock Z value
Buy a vertical
CUI
CUI
It is Better to
Alert users and let them cancel
Put on locked layers, Use file permissions, Send DWF or
PDF, Train workers
Send DWF or PDF, Use file permissions, Archive safe
copies, buy Cadlock. Notice I didnt promote passwords
20
CP311-4
:VLR-Insert-Reactor
:VLR-Linker-Reactor
:VLR-Lisp-Reactor
:VLR-MiscellaneousReactor
:VLR-Mouse-Reactor
:VLR-Object-Reactor
:VLR-Sysvar-Reactor
:VLR-Toolbar-Reactor
:VLR-Undo-Reactor
Their Specialties
Monitor changes in the database. They are very active and should be
used sparingly.
They monitor commands, when they start, when they end, if they are
cancelled and if they are unknown or failed.
Excels in tracking copied objects
Tracks when documents are opened, destroyed, locked, became
current, will be activated, or will be deactivated. When adding entities,
it triggers often. It watches when you pop to another application.
Tracks when the drawing will be closed, deleted, opened or saved.
Whether some events will trigger depends on whether SDI=0 or 1
Tracks operations related to dxfin and dxfout
A combination of the capabilities of VLR-Command-Reactor, VLR-DWGReactor, VLR-Lisp-Reactor, and the VLR-Sysvar reactor. I suggest using
the others. You should avoid using both for the same event.
Tracks operation related to inserting blocks or drawings. When
inserting other drawings, there is a translation matrix involved that
controls scaling, translation, and rotation.
Tracks when ObjectARX application are loaded and unloaded
Tracks when lisp expressions entered at the command line begin, end,
and are cancelled. Useful for cleanup behind lisp commands that
change variables and turn over control to AutoCAD commands for
prompting.
Tracks when the pickfirst selection set changes and when the layout
changes
Tracks double-clicks and right-clicks. Prior to AutoCAD adding these
events to the CUI, this was the only way to customize these actions in
relation to object types.
A watch selected Owner objects and notifies when those objects are
copied, erased, un-erased, deleted from memory, opened for
modification, modified, un-appended, re-appended and unmodified.
Formerly, this was the only way LISP programmers had to implement
custom objects.
This is a very active reactor and may trigger multiple times for each
command. Can be very useful.
Tracks when toolbar icon sizes will change or has been changed.
Tracks subcommands of the undo command (Auto, Control, Begin, End,
Mark, Back, and Number)
21
CP311-4
Data is a placeholder for anything you want stored with the reactor itself. This eliminates the
need to maintain global variables to maintain transitions between events.
Callbacks is a quoted association list that contains dotted pairs in the form (event . callback)
where callback is the name of a user defined function usually accepting 2 arguments (object
reactors 3).
Event is a specially named variable that is bound to its name. Example names are :VLRCommandWill-Start, :VLR-CommandEnded, or :VLR-ObjectModified. These names are not
case sensitive but are written that way to improve readability.
For most reactors the first argument is the calling reactor and the second argument is a
parameter list that varies for each reactor type and each event type within that reactor type.
The help files are the best source of information when writing the callback functions.
be reasonably stable. Since callbacks are so important, it might be better to define them in a
separate namespace VLX application (beyond the scope of this course).
Generalized format:
Example:
23
CP311-4
Format
Action
Returns
VLR-owner-add
(VLR-owner-add reactor
ownerobject)
Ownerobject
VLR-owner-remove
(VLR-owner-remove
reactor ownerobject)
Removes an owner
from the reactor
Ownerobject
VLR-Owners
(VLR-owners reactor)
Identifies Owners of a
reactor.
Object Callbacks are powerless over their notifiers: They receive notifications but they
cannot change the state of the notifying objects (called notifiers). Callbacks for :VLRopenedForModify cannot even access an objects properties without causing errors. There only
power with respect to the notifiers is to pass references to them on to other reactors that have
power to change.
24
CP311-4
VLR-Function
General format
What it does
Returns
VLR-Pers
(VLR-pers reactor)
reactor
VLR-Pers-p
(VLR-pers-p reactor)
T or nil
VLR-persrelease
(VLR-pers-release
reactor)
Reactor or nil
Keep Me Informed
Reactors normally fire only for events that relate to the current database. It is possible to have a
document level reactor be notified by changes/events occurring in other documents.
Experiment with notification settings when working with dummy callbacks to understand the
differences.
VLR-notification
Determines whether or not a reactor will fire if its associated namespace
is not active. The return value is either all-documents or active-document-only.
VLR-set-notification Defines whether a reactor's callback function will execute if its associated
namespace is not active. Format: (VLR-set-notification reactor range) where range is either
all-documents or active-document-only.
Be careful using reactors that respond to other documents. Each document has its own
namespace and variables in one drawing are not available to the reactor being triggered in
another document. In fact most lisp code is suspended until a document is reactivated. It is
entirely possible that reactors whose notification setting is all-documents might continue to
execute after their host document is closed.
Whos on First?
When designing your reactor system do not depend on the order of the reactions or on the order
of events. When object reactors fire, they generate a callback call for each tracked object and
for each tracked event.
Regressive Behavior
Dont forget the importance of handling undo/redo events. If ignored or improperly handled the
system will report errors. In the worst case, you can end up with unpredictable events. The
object reactors are capable of notifying during undo events. At the very least, you should
dummy out the undo callbacks to understand when things happen. Some experts believe that
25
CP311-4
Format
Use
Returns
VLR-remove
(VLR-remove reactor)
Reactor (a vla-object)
VLR-remove-all
(VLR-remove-all)
Reactor list
Function
Format
Use
Returns
VLR-add
(VLR-add reactor)
Reactor (a vla-object)
VLR-added-p
(VLR-added-p reactor)
T or Nil
Too Much to Do
Reactors, if used sparingly can be a blessing. It is possible however to completely shut down
the system with reactor calls. Be sure to turn reactors on and off when you need them.
26
CP311-4
Calling Format
(VLR-data-reactor)
VLR-types
(VLR-types)
(VLR-type reactor)
Why use?
To access data stored in reactor
To store data in a reactor
Returns a symbol representing the
reactor type.
Returns a list of symbols
representing all reactor types
Returns
Expression or nil
Expression or nil
Symbol
List
27
CP311-4
This code will automatically create dummy reactors for every event that the specified reactor
has. It can quickly identify opportunities to take advantage of the reactor system.
In conclusion, reactors can be useful but should only be considered if other built-in offerings of
AutoCAD are missing the capabilities you desire.
My main uses for reactors have been 1)to serve as cleanup functions for Lisp implemented
commands that seek to auto layer and 2) to modify textsize, dimscale, and ltscale as part of a
custom annotation management system (This use should now be obsolete as well).
28
CP311-4
Excel
Workbooks
Workbook
Worksheets
Ran
ange
Excel has such good developer documentation that it is easy to prototype the application in VBA
and then to translate into Vlisp. The need for such custom access to Exc
Excel
el however has greatly
diminished with recent advancements in tables and in data extraction. In fact, its
it difficult to
imagine a task involving Excel that AutoCAD itself cant do well. The following sample
illustrates VBA vs. LISP methods to access a va
value
lue in a single cell named range in an Excel
Workbook. The initial setqs above defun are for testing and debugging as illustrated in class.
(setq XL (vlax-get-or-create-object
object
"Excel.Application"))
(setq WBKS (vlax-get-property
property XL 'workbooks))
(setq WBK (vlax-invoke
invoke WBKS 'open FileSpec))
(setq SHTS (vlax-get-property
property WBK 'worksheets))
(setq SHT (vlax-get-property
property SHTS 'item ShtName))
(setq RNG (vlax-get-property
property SHT 'RngName
RngName))
(setq VAL (vlax-get RNG 'value))
(princ VAL)
(mapcar 'vlax-release-object
object (list RNG SHT SHTS))
(Vlax-invoke
invoke WBK 'close) ;Steps of closing
(vlax-invoke XL 'quit)
(vlax-release-object XL) )
29
CP311-4
2. Classify objects by type and direct the appropriate actions by conditional branching:
4. Mistaking objects for collections can be avoided by looking at the object model, by
using help files, by dumping object properties and by checking whether a count
property or an item method is applicable.
5. Check to see if objects are referenced prior to deleting them. Since this is difficult to
do using vla-methods, trap the inevitable error. See next section.
30
CP311-4
Using library catchall conversion routines is generally bad practice. Know what is
coming and use the built
built-in functions to work with the data.
7. To avoid errors caused by accessing erased objects, either test to see if they were
erased or dont keep the objects long term. (vla
(vlax-erased-p
p object) can be used to
test before accessing the potentially erased object.
The vl-catch-all-apply
apply process above is poorly written mistaken code. Mistakes are:
1. It assumes that vl
vl-catch-all-apply
apply is like mapcar rather than apply.
2. It does not save the results of the vl
vl-catch-all-apply
apply operation. So there will
be no future opportunity to test the error.
31
CP311-4
Error handlers
Each susceptible user defined function should contain an error handler that cleans up after
itself and reports the errors.
Bad parenthesis matching. Vlide usually can catch it but not always. Double click
on each parenthesis to see the enc
enclosing code. Check each step.
2.
3.
32
CP311-4
2.
3.
Local variables and loop variables do not need to be released. The garbage
collector is smart enough to recover space and to reset pointers when local
variables go out of scope.
The code above checks to see if the variable is bound to a value before attempting to
release it. An attempt to release an object not bound to an object will generate an
unnecessary error.
When in doubt, release the object!
In conclusion: 1) Use VLIDE, 2) Keep the Help files open, 3)Program for single line
testing, 4)Dump and examine objects, 5) Dont program before you explore current
AutoCAD features, 6) Comment thoroughly, 7) Use error handlers ,8) Clean-up after
execution, 9) Be careful using reactors, and 10) Command and DXF methods have
their place. Dont expect Vlisp to do everything.
Thank you for attending this Class! Hope youve enjoyed it. Please dont forget to fill
out your feedback report.
33
CP311-4