Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Autocad 2005 And Autocad LT 2005 Bible (2004).pdf
Скачиваний:
92
Добавлен:
17.08.2013
Размер:
32.22 Mб
Скачать

1028 Part VII Programming AutoCAD

(setq new_str (getstring)) (setq src_object

(subst (cons 40 new_ht) (assoc 40 src_object) src_object)

)

(setq src_object

(subst (cons 1 new_str) (assoc 1 src_object)src_object)

)

(entmod src_object)

)

(princ “You must select a text object.”)

)

(princ)

)

4.Load ab35-06.lsp. Start chgmytext and try out the routine again with a circle or other non-text object.

Don’t save your drawing.

Summary

In this chapter, you read about how to create variables, create AutoLISP functions, and work with AutoCAD commands and system variables. You extended AutoLISP’s power by using lists and looping. This chapter explained how to modify and get information about drawing objects. You also read about how to create selection sets. Using these techniques, along with user input, you can automate the modification of objects in your drawing to suit your needs.

You should always finish off your AutoLISP routines by adding some error handling, making sure the routine exits quietly, and adding helpful comments about the routine’s function.

In the next chapter, you read about some of the more-advanced features of Visual LISP.

 

 

 

Exploring Advanced

AutoLISP Topics

This chapter builds on the previous two chapters and introduces you to a few helpful advanced AutoLISP topics, including local

and global variables, ActiveX, and debugging.

AutoCAD LT does not support AutoLISP, so this entire chapter is for AutoCAD only.

Understanding Local and

Global Variables

In this section, you read how local and global variables are accessed within a function, as well as some common syntax. You also discover what can happen when global variables are not properly documented.

Chapter 35 explained that a variable is a symbolic name that can be operated on in a given program. An important part of using variables is being able to assign values to them. There are two types of variables — global and local.

A global variable is exposed, or available, to all AutoLISP functions that you’ve loaded into your drawing. A global variable retains its value after the program that defined it is finished. You use a global variable when you want its value to be available across an entire project as opposed to just one function within a project, to retain a fixed value that might be used and assigned by different functions, or for debugging. Any variable you don’t specifically define as a local variable is a global variable.

A local variable is temporarily assigned a value during a function’s execution. After the function completes executing, the local variable value is discarded. AutoLISP can now use the memory that was taken up by that local variable. You use a local variable when you want to be sure you don’t have variable values floating around interfering with other functions. Local variables are also easier to debug because they only affect the code within their function. In general, most of your variables should be local. You create a local variable and declare it in the DEFUN statement after the slash and a space, as in this example:

36C H A P T E R

In This Chapter

Understanding local and global variables

Working with Visual

LISP ActiveX functions

Debugging code

Using the Error

Trace window

Using the Watch window

(defun list-objects ( / counter sset)...

1030 Part VII Programming AutoCAD

Caution

Global variables can be tricky. They can easily cause bugs; their values persist and can be

 

hard to debug because the values are hard to find. A common syntax for global variables is

 

to prefix and suffix the variable with an asterisk as in *aGlobal*. In this way, you can easily

 

identify global variables in your code. Keep your use of global variables to a minimum and

 

carefully document those you do use. Failure to follow these simple rules could result in

 

undesirable and difficult-to-trace bugs.

STEP-BY-STEP: Using Local and Global Variables

1.Start a new drawing using the acad.dwt template. You should not have any other drawing open.

2.Open the Visual LISP Editor.

3.In the Console window, type the following line and then press Ctrl+Enter. You use Ctrl+Enter in the Console window to enter in code of more than one line. This line declares one local variable:

(defun local-variable (/ var1)

4.Type the second line of code in the Console window as follows:

(setq var1 “I’m local”))

This sets the local variable to the string you typed. The Console returns the name of the function:

LOCAL-VARIABLE

5.Before you test this function, you can check out the current value of the local variable: var1. Type var1 in the Visual LISP Console. The Console returns

nil

As you can see, the value is nil.

6.Test the local-variable function to check the value it sets to the var1 variable. In the Console, type (local-variable) . The Console returns

“I’m local”

You now know that the local-variable function definitely assigns the value of “I’m local” to the variable var1.

7.To create a global variable, type (setq var1 “I’m global”) in the Console. The Console returns

“I’m global”

You know that the value of var1 is now “I’m global”.

8.Test the local variable again by typing (local-variable) in the Console. The Console returns “I’m local” because it executes the local-variable function.

9.Test the variable var1 to see what its value is now. In the Console, type var1 . The Console returns “I’m global”. The local variable was not retained when the function used the variable because the variable was local to the function. However, the global variable’s value persisted.

Chapter 36 Exploring Advanced AutoLISP Topics 1031

Working with Visual LISP ActiveX Functions

ActiveX is an interface that exposes objects to the user, a programmer, or an application. AutoLISP supports ActiveX, giving you more information and flexibility in working with your drawings. You can also use ActiveX to work with objects in other Windows applications that support ActiveX. ActiveX is a programming interface that is used within a programming language that supports it. For example, you can also use ActiveX with Visual Basic for Applications (see the next chapter) and C++.

Cross-

In ActiveX, objects are structured in a hierarchy. You need to understand this structure before

Reference

working extensively with ActiveX. Chapter 37 covers this hierarchical structure in more detail.

 

ActiveX enables you to get information about objects (called get functions) and modify them (called put functions). The next section first reviews how you create these two functions in AutoLISP.

Reviewing AutoLISP retrieval and modification

In this section, you look at developing a small routine, written in AutoLISP, that mimics ActiveX properties and methods. This will help you compare how AutoLISP works compared to ActiveX.

To understand Visual LISP’s ActiveX features, you need to know how AutoCAD exposes an object’s properties in AutoLISP. The following examples work with a line 10 units long created using the following AutoLISP function:

;;; This function creates a line using the AutoLISP

;;; command function and returns nil. (defun make-aLine ()

 

(command “_line” “5,5” “15,5” “”)

 

)

Note

The uppercase letter (in the function name) is used for readability, but you can type all lower-

 

case letters if that’s easier for you.

After loading it, you can use this function (that is, draw the line) by typing the following at the Visual LISP Console:

(make-aLine)

As explained in Chapter 35, to retrieve the last object created (the line), you use ENTLAST as shown in the following code fragment. The next expression places the value of the last created entity, as an entity name, to the variable LineEntity. To try this out, type the following code in the Console.

(setq LineEntity (entlast))

Visual LISP responds with the entity name. As soon as you receive the entity name, you can use ENTGET to retrieve the object property list of the line entity name. The following code fragment places the property list value in the variable LinePropertyList. If you type the following in the Console and press Enter, Visual LISP responds with the property list:

(setq LinePropertyList (entget LineEntity))

1032 Part VII Programming AutoCAD

Here is an example of a property list, formatted for readability.

((-1 . <Entity name: 1456d60>) (0 . “LINE”)

(330 . <Entity name: 1456cf8>) (5 . “2C”)

(100 . “AcDbEntity”)

(67 . 0)

(410 . “Model”) (8 . “0”)

(100 . “AcDbLine”)

(10 5.0 5.0 0.0)

(11 15.0 5.0 0.0)

(210 0.0 0.0 1.0))

As you can see, ENTGET returns an entity’s properties as a collection of lists, all of which have a distinctive number at their first position. These group codes (also commonly known as DXF fields, because you can also find them in DXF files) were listed in Chapter 35. For this exercise, you just need to remember that the 10 group code is associated with the start point of a line.

Having the entity list and knowing which values to retrieve, you can use the AutoLISP function ASSOC, which returns an associated item from a property list.

To retrieve the start point of the line, you would use the following code, which you can type in the Console:

(setq StartofLineList (assoc 10 LinePropertyList))

The Console returns the list associated with the 10 group code, including the group code and the coordinates:

(10 5.0 5.0 0.0)

Because the only value you require is the start point of the line object, use the function CDR to remove the first element of the list, as shown in the following code.

(setq StartofLine (cdr (assoc 10 LinePropertyList)))

This code returns only the start point coordinate:

(5.0 5.0 0.0)

Now that you’ve reviewed how to retrieve a value from an AutoCAD object, you can see that retrieving information from an associated list is somewhat straightforward. But how about retrieving more than one property at a time? As you can see from the preceding example, you’d have to repeat the same body of code many times over to retrieve any information. Knowing this, you could write a simple interface function, putting together all the steps just explained, to retrieve any group code, not just the 10 group code, from an object.

Note An interface function is a function that hides a complex behavior to the user. The user need provide only basic information, but the function uses the information in several steps to obtain the desired result.

Chapter 36 Exploring Advanced AutoLISP Topics 1033

An example of an interface function is shown in the following lines:

;;;returns any group code value if it is present in the entity

;;;the required parameters are an entity name and a group code. (defun Get-A-Group-Code (EntityName GroupCode)

(cdr (assoc GroupCode (entget EntityName)))

)

After you create this function and load it, you can test it out in the Console as follows, using the LineEntity variable previously defined:

(Get-A-Group-Code LineEntity 10) (5.0 5.0 0.0)

As you can see, the function returns only the value of the 10 group code.

You can refine this small interface by defining a separate 10 group 10 function, such as the following. The only required parameter is an entity name. The group code is included in the call to Get-A-Group-Code. You could do the same for an 11 group code, if you want.

(defun Get-Group-10-Code (anEntityName) (Get-A-Group-Code anEntityName 10)

)

After loading, test the function, as follows:

(Get-Group-10-Code LineEntity)

Visual LISP returns the start point of the line:

(5.0 5.0 0.0)

These examples summarize how you would create a simple function to get the start point

of a line using AutoLISP. What if you need to change an object’s property? You can do this by using the functions CONS, SUBST, and ENTMOD, which Chapter 35 covers.

CONS constructs a list. Use it when you want to create new values for a group code within an entity list, as in the following example, which you can type in the Console window:

(setq NewStartPoint (cons 10 ‘( 0 0 0 )))

Visual LISP returns the following:

(10 0 0 0)

Using the variables NewStartPoint and LinePropertyList, you can now substitute the newly created group 10 code. You do this using the SUBST function explained in Chapter 35. The following code substitutes the new group 10 code represented by the variable NewStartPoint for the 10 association in LinePropertyList in the list called LinePropertyList.

(Setq LinePropertyList

(subst NewStartPoint (assoc 10 LinePropertyList)

LinePropertyList)

)

1034 Part VII Programming AutoCAD

To test this out, type the preceding code in the Console window. To see the new start point, you need to scroll all the way to the right. The list (nicely formatted) now has a new group 10 value (the start point), shown on the third-to-last line that follows:

((-1 . <Entity name: 1456d60>) (0 . “LINE”)

(330 . <Entity name: 1456cf8>) (5 . “2C”)

(100 . “AcDbEntity”)

(67 . 0)

(410 . “Model”) (8 . “0”)

(100 . “AcDbLine”)

(10 0 0 0)

(11 15.0 5.0 0.0)

(210 0.0 0.0 1.0))

To reflect the modification of this line in AutoCAD, as explained in Chapter 35, you can now use the function ENTMOD, as follows, by typing it in the Console. This code actually changes the start point of the line. (You can return to AutoCAD to check it out.)

(entmod LinePropertyList)

As you can see from this example, getting object properties and modifying them can be a tedious and time-consuming process. For the next example, you write an interface function that modifies any group code contained in any object.

(defun put-group-code-value (Entityname Groupcode Value / PropertyList)

(setq PropertyList (entget EntityName)) (setq PropertyList

(subst

(cons GroupCode Value)

(assoc GroupCode PropertyList) PropertyList

)

)

(entmod PropertyList)

)

This function combines all the preceding steps into one function. Here’s how it works:

Line 1 defines the function with three arguments: the entity name, a group code, and a new value for the group code. It also declares a local variable, PropertyList, which is the property list of the object.

Line 2 sets the property list equal to the ENTGET of the entity name.

Line 3 starts the process of setting the same property list to the new value.

Lines 4 through 7 execute the substitution. They substitute the new group, created by (cons GroupCode Value), for the current group value, created with the ASSOC function, in the property list named PropertyList.

Line 8 closes the SUBST function.

Chapter 36 Exploring Advanced AutoLISP Topics 1035

Line 9 closes the second SETQ function.

Line 10 modifies the drawing database using ENTMOD.

Line 11 closes the DEFUN function.

Using the preceding function, you now have a much simpler interface for modifying any group code. Next, you use the function Put-Group-Code-Value to modify the 10 group code of the line object.

After entering and loading the preceding function, you can test the function by typing the following in Visual LISP:

(Put-Group-Code-Value LineEntity 10 ‘(5 5 0))

This function changes the start point of the line to 5,5,0.

Using the same logic to write the get functions, you can now define a separate 10 group code modifier function. You can do the same for any group code.

(defun Put-Group-10-Code (EntityName Value) (Put-Group-Code-Value EntityName 10 Value)

)

After entering and loading this function, type the following at the Console to change the start point of the line to 15,–5,0.

(Put-Group-10-Code LineEntity ‘( 15 -5 0 ))

Activate AutoCAD to check that the line has been changed.

Using ActiveX with Visual LISP

ActiveX enables you to retrieve and modify objects similar to the method used in the previous section of this chapter, but it requires some preparation. In the following section, you read about using some ActiveX functions to create, retrieve, and modify an object.

Retrieving and modifying object information with ActiveX

Visual LISP enables you to retrieve and modify any AutoCAD object using AutoCAD’s ActiveX interface. That is to say, AutoCAD exposes all of its objects to ActiveX-enabled applications. This includes Visual LISP as ActiveX objects, all of which expose their properties, including put (modify) and get (retrieve) functions.

Using Visual LISP to communicate with AutoCAD is very straightforward. You must first load all the ActiveX functions using the VL-LOAD-COM function within Visual LISP. This exposes all the ActiveX interface functions. You need to load the VL-LOAD-COM function only once each time you open AutoCAD, because VL-LOAD-COM loads the ActiveX functions for the entire drawing session. (Using VL-LOAD-COM more than once, however, doesn’t cause any harm.) To load VL-LOAD-COM, enter it on the command line:

(vl-load-com)

After the ActiveX interface is loaded, you can interrogate the line you created previously, but first you need to convert the entity name into a vla-object. A vla-object is no different from an entity name, except that the ActiveX object exposes certain properties that its AutoLISP

1036 Part VII Programming AutoCAD

counterpart does not. To convert the entity name into a vla-object, you use the function

VLAX-ENAME->VLA-OBJECT, as shown here:

(setq vla-line (vlax-ename->vla-object (entlast)))

Visual LISP returns the following:

#<VLA-OBJECT IAcadLine 03612b14>

As you can see by the return value of vlax-ename->vla-object, the value of the variable vla-line contains a vla-object. At this point, you can visually inspect the variable by selecting it and choosing View Inspect. Although you see the line’s property in a dialog box, you can also “dump” its property and values to the Console by using the VLAX-DUMP-OBJECT Visual LISP function as follows:

(vlax-dump-object vla-line)

This causes Visual LISP to display the following:

;IAcadLine: AutoCAD Line Interface

;Property values:

;Angle (RO) = 1.5708

;Application (RO) = #<VLA-OBJECT IAcadApplication 00af9594>

;Delta (RO) = (0.0 10.0 0.0)

;Document (RO) = #<VLA-OBJECT IAcadDocument 038be900>

;EndPoint = (15.0 5.0 0.0)

;Handle (RO) = “89”

;HasExtensionDictionary (RO) = 0

;Hyperlinks (RO) = #<VLA-OBJECT IAcadHyperlinks 01011d44>

;Layer = “0”

;Length (RO) = 10.0

;Linetype = “ByLayer”

;LinetypeScale = 1.0

;Lineweight = -1

;Normal = (0.0 0.0 1.0)

;ObjectID (RO) = 2130009736

;ObjectName (RO) = “AcDbLine”

;OwnerID (RO) = 2130009336

;PlotStyleName = “ByLayer”

;StartPoint = (15.0 -5.0 0.0)

;Thickness = 0.0

;TrueColor = #<VLA-OBJECT IAcadAcCmColor 01015170>

;Visible = -1

T

You’ll probably have to resize the window to see all these properties. Notice the similarities between the “named” properties shown here, such as EndPoint and StartPoint, and the line’s group codes that you retrieve using AutoLISP. As you can see, one of the advantages of using an ActiveX-enabled object is that ActiveX exposes more information to the programmer than standard AutoLISP. One of the benefits of using ActiveX is its interface. Previously, you queried and modified a line object’s start point and endpoint by using the 10 and 11 group codes. Using ActiveX to query the start point and endpoint is very straightforward. However, ActiveX returns these points in a data type called a variant that you need to convert to the familiar coordinate format.

Chapter 36 Exploring Advanced AutoLISP Topics 1037

To get the start point of an object, you use the VLA-GET-STARTPOINT function. In the current example, the line has been set to vla-line, so you would type the following expression:

(setq Starting (vla-get-startpoint vla-line))

Visual LISP responds as follows:

#<variant 8197 ...>

To convert the start point from the variant data type to a usable coordinate format, you would type the following line:

(safearray-value (vlax-variant-value Starting))

Visual LISP responds with a coordinate:

(15.0 -5.0 0.0)

To modify the StartPoint property of a line to (0,0,0) you would use the following expression:

(vla-put-startpoint vla-line (vlax-3d-point ‘(0 0 0 )))

You can return to AutoCAD to check out the line. To verify the new StartPoint you can also use the VLA-GET-STARTPOINT function:

(safearray-value (vlax-variant-value (vla-get-StartPoint vla-line)))

Visual LISP returns the start point of the line:

(0.0 0.0 0.0)

As you can see, this is very similar to the small routine developed in AutoLISP earlier in this chapter.

STEP-BY-STEP: Retrieving and Modifying Objects with ActiveX

1.To start a new drawing session, close AutoCAD if it’s open. Open AutoCAD.

2.Start a new drawing using the acad.dwt template.

3.Draw any line. Neither the start point nor the endpoint should be 0,0,0.

4.Choose Tools AutoLISP Visual LISP Editor.

5.In the Console window, type (vl-load-com) to load the ActiveX functions.

6.To convert the entity name into a vla-object, type (setq vla-line (vlax-ename->vla-object (entlast))) .

7.To view the line’s properties, type (vlax-dump-object vla-line) .

8.To get the start point of the line, type (setq Starting (vla-get-startpoint vla-line)) .

9.To convert the start point from the variant data type to coordinate format, type

(safearray-value (vlax-variant-value Starting)) .

10.To change the line’s start point to 0,0,0, type (vla-put-startpoint vla-line (vlax-3d-point (0 0 0 ))) .

11.Choose Activate AutoCAD on the Visual LISP View toolbar to check out the line. Its start point is now 0,0,0.

; retrieve the model ; space object
; get the current ; active document
; get the acad object
; starting point ; ending point

1038 Part VII Programming AutoCAD

Creating objects with ActiveX

This section looks at object-creation functions. When you work with ActiveX you need to retrieve objects in their hierarchical order. This hierarchy concept is discussed in more detail in the next chapter. For this chapter, you need to know that before you can retrieve an object, you need to retrieve the following:

Acad-object: Represents the AutoCAD application.

ActiveDocument: Represents your drawing.

ModelSpace/PaperSpace: Represents the type of space you want to use within the AutoCAD application.

In AutoLISP, you first retrieve the space (model or paper), then your drawing, and finally the AutoCAD application. Here you take the simple line command used earlier in this chapter and convert it using ActiveX:

;;;This function creates a line using Visual LISP

;;;ActiveX and returns the line object as a vla-object. (defun ax-make-aLine ()

(vla-AddLine

(vla-get-ModelSpace

(vla-get-ActiveDocument

(vlax-get-acad-object)

)

)

(vlax-3d-point ‘(5 5 0)) (vlax-3d-point ‘(15 5 0))

)

)

You can type this in the Visual LISP Editor and load it. To try it out, type the following in the Console:

(ax-make-aLine)

Visual LISP responds with the following:

#<VLA-OBJECT IAcadLine 03614934>

This might seem a little cumbersome — as if it might be a lot of work to create a line — but quite honestly, it isn’t. It’s actually quite flexible.

To locate other ActiveX functions that create objects, you need to look in the AutoCAD ActiveX and VBA Reference. In Visual LISP, choose Help, Visual LISP Help Topics. From the Contents tab, double-click ActiveX and VBA Reference, and then Methods. You immediately see an alphabetical list with the A’s displayed. Here are all the VBA methods that add drawing objects. To create a Visual LISP function, add VLA- before the method. For example, to add a circle, you would use VLA-AddCircle.

Tip

You immediately know if the function is correct, because it turns from black to blue as you

 

enter it.