Get it to any device in seconds. Autocad visual lisp tutorial. Previous page Next page. Publish for free today. Go explore. Double-click on any file to open the file in the VLISP text editor if it is not already open and make it the active editor window.
Adding the Dialog Box Interface The next part of this lesson concerns adding a dialog box interface to the garden path application. To do this, you will be working with another language, dialog control language DCL. Currently, your gpath function only accepts input at the Command line. You included a stubbed-out function gp:getDialogInput with the intention of adding a dialog box interface. Now is the time to add the interface.
Define the appearance and contents of the dialog boxes. Add program code to control dialog behavior. Two sets of radio buttons. One set of buttons determines the polyline style of the boundary, and the other set of buttons specifies the tile entity creation method ActiveX, entmake, or command. Only one radio button in a set can be selected at one time.
Edit boxes for specifying the radius of tiles and the spacing between tiles. A standard set of OK and Cancel buttons. Dialog box components are referred to as tiles in DCL. Writing the complete contents of a dialog box DCL file may seem overwhelming.
The trick is to sketch out what you want, break it down into sections, then write each section. This DCL statement defines the title of the dialog box window.
Each radio button requires a label and a key. A value of 1 a string, not an integer assigned to a button makes it the default choice in a row of buttons. In other words, when you first display the dialog, this button will be selected. Notice that this definition does not set any initial values for the edit boxes. In this case, your DCL file defines just a single dialog box, so there is no choice to be made. As you create larger and more robust applications, however, you may end up with DCL files containing multiple dialog boxes.
If AutoCAD finds syntactical errors, it displays one or more message windows identifying the errors. The stubbed-out function, gp:getDialogInput, is where this activity will take place. This function now lives in the gp-io.
Developing a dialog box interface can be confusing the first few times you do it. Does the dialog box need to be set up with default values? What happens when the user presses a button or enters a value? What happens when the user presses Cancel? If the dialog. Setting Up Dialog Values When you run the complete garden path application, notice that the dialog box always starts up with ActiveX as the default object creation method and Lightweight as the polyline style.
Something more interesting occurs with the default tile size—the values change depending on the width of the path. The following code fragment shows how to set up the default values to be displayed in the dialog box: setq. This becomes apparent in the next two sections. This function searches for dialog files according to the AutoCAD support file search path, unless you specify a full path name. You will see this in a moment.
For now, take a look at how you need to load in your dialog: ;; Load the dialog box. The dialogLoaded variable indicates if the dialog loaded successfully. In the code where you set up the initial values for the dialog box, you set dialogLoaded to an initial value of T.
As you can see in the code fragment above, dialogLoaded is set to nil if there is a problem with the load. The next step in using a dialog is to specify which dialog box definition to display. If there are multiple expressions evaluated within an and function call, evaluation of subsequent expressions is terminated with the first expression that evaluates to nil.
In this case, if the. Notice that the code also accounts for the possibility that something might not be working properly with the DCL file, and sets the dialogShow variable to nil if that is the case. Initializing the Default Dialog Values If everything worked successfully in loading the dialog, you are ready to start setting up the values that will be displayed to users.
A successful load is indicated if the flag variables dialogLoaded and dialogShow are both T true. Now set the initial values for the tile radius and spacing. An edit box deals with strings rather than numbers, so you need to use the rtos convert Real TO String function to convert your tile size variable values into strings in decimal format with a precision of two digits.
The string anything within double-quotation marks is dormant until the user selects the tile. Look at one more code fragment. Then atof converts the number string into a real number. The next thing to do is to put it all in motion. Users can make choices within the dialog box, until they press the OK or Cancel buttons. This list is what gp:getDialogInput will return to its calling function. Putting the Code Together With the examples above, and a few additional lines, you have the code needed to complete the gp:getDialogInput function.
To put gp:getDialogInput together 1 Open your copy of gp-io. The function expects a single argument pathwidth , and establishes a number of local variables. Those fragments just repeat pieces of the example. Has the defun statement changed? That is, does the function still take the same number of arguments? Does the function return something different?
In the case of gp:getDialogInput, the answer to both questions is yes. The function now accepts the parameter of the path width to set the default tile size and spacing.
And instead of returning T, which is the value the stubbedout version of the function returned, gp:getDialogInput now returns an association list containing four new values. Both changes affect the code that calls the function and the code that handles the return values from the functions. Replace your previous version of the C:GPath function in gpmain.
Take a look at the boldface lines in the revision of the main C:GPath function. When the gp:getDialogInput function is invoked, the path width is passed to it. There are additional changes in the code resulting from the replacement of placeholders in the stubbed-out version.
The easiest thing to do is copy this code from the online tutorial and paste it into your file. Providing a Choice of Boundary Line Type One requirement specified for the garden path application was to allow users to draw the boundary outline as either a lightweight polyline or an old-style polyline.
The first version of gp:drawOutline you wrote always used a lightweight polyline to draw the boundary. Now that the dialog box interface is ready to go, you can build in the option for drawing an old-style polyline as well. To accomplish this, gp:drawOutline must determine what kind of polyline to draw, and then it must draw it. The necessary changes to gp:drawOutline are included in the following code fragment.
Make the modification from the gpdraw. Typing the changes into your code can be very tricky, as you not only need to add code but also to delete some existing lines and rearrange others. It is recommended you copy the entire setq statement from the online tutorial and paste it into your code.
Cleaning Up If you have not done so already, delete the following chunk of code from the C:GPath function in gpmain. You had been using this code as a placeholder, but now that gp:drawOutline is functioning, you no longer need it. Running the Application Before running your program, save all the files you changed, if you have not already done so. Click Open. If you have some debugging to do, try using the tools you learned in Lessons 2 and 3.
Also, try drawing the path using both lightweight and old-style polylines. After drawing the paths, use the AutoCAD list command to determine whether or not your program is drawing the correct entity types. Modularized your code by dividing it among four files.
Modified your code to provide users with a choice of boundary line type. Now you have a program that draws a garden path boundary. In the next lesson, you will add the tiles to the garden path. Editing Tools basic requirements stated in Lesson 1. You will add the functionality for drawing tiles within the boundary of the garden path and provide this function using several. You will also learn some keyboard shortcuts and new editing tools.
There are a couple of things about this code that are typical of much of the code you will be developing with VLISP. First, there are many parentheses and parentheses within parentheses. Second, there are many function calls, and some of those functions have very long names vla-addLightweightPolyline, for example.
Matching Parentheses VLISP provides a parenthesis matching feature to help you find the close parenthesis that corresponds to an open parenthesis. To match an open parenthesis with its corresponding close parenthesis 1 Place your cursor in front of the opening parenthesis that precedes the setq function call. Double-clicking also does the trick. VLISP finds the closing parenthesis that matches the one you chose, and selects all the code in between. Not only does this ensure you typed in the correct number of parentheses, it also makes it easy to copy or cut the selected text.
This might have come in handy when you updated this call at the end of Lesson 4. Why else might you want to do this? Or maybe you have figured out how to replace 50 lines of code with three really marvelous lines of much better code. You can quickly select the old code using the parentheses matching tool, then eliminate it with a single keystroke. It is a lot quicker to let VLISP find an entire block than for you to hunt down every last closing parenthesis.
There is a corresponding key command for matching and selecting backward. VLISP searches for the corresponding opening parenthesis, and selects it along with the enclosed code. It is only an example that includes several long variable and function names. VLISP can save you some keystrokes by completing words for you. VLISP just saved you seventeen keystrokes as it searched within the current file and found the closest match to the last two letters you typed. However, the word you need is polar.
Eventually, it will come around to polar. Often, it is confusing to keep track of all the selection set functions: ssname, ssget, sslength, and so on. Use the cursor keys the up and down arrow keys to move through the list. Getting Help with a Function The code that adds a lightweight polyline to the drawing calls a function named vla-addLightweightPolyline.
Not only is that a lengthy term to write, but there are several functions whose names begin with vla-add that you will use to create entities. Rather than consulting a manual to look up the function name every time you create a program, let VLISP help.
To get help with using a function 1 Enter the following on a blank line: vla-add. Also, close the Symbol Service and Apropos windows. Adding Tiles to the Garden Path You now have a path boundary and are ready to fill it with tiles. You will need to apply some logic and work through a little geometry.
Applying Some Logic One thing you need to do is determine how to space out the tiles and draw them. But for the garden path, you need to have each row of tiles offset from the previous row. This row-offset pattern is a repeating pattern. Think of how you might go about laying the tiles if you were building the actual path.
While the space of the boundary filled is less than the space to fill, Draw a row of tiles. Add the distance filled by the new row to the amount of space filled. Toggle the offset if it is centered, set it up off-center, or vice versa. Go back to the start of the loop. Applying Some Geometry There are only a few dimensions you need to know to draw the garden path.
The half width is easy: it is just half the width of the path. You already defined the code to obtain this width from users and saved it in an association list. Tile spacing is also easy; it is twice the radius that is, the diameter plus the space between the tiles.
The dimensions are also obtained from users. Row spacing is a little trickier, unless you are really sharp with trigonometry. Drawing the Rows See if you can make sense of the following function. Compare it to the pseudo-code and try to catch the geometric calculations just described. For now, just read the code; do not write anything. A couple of sections from the code may need a little extra explanation.
The following code fragment occurs right before the while loop begins: ;; Compensate for the very first start point!! The rowStartPoint variable starts its life within the gp:Calculate-and-Draw-Tiles function by being assigned the point the user selected as the start point of the path.
Another way of stating this is: At the time the gp:calculate-Draw-TileRow function is called, the rowStartPoint variable is set to one RowSpacing distance beyond the current rowStartPoint. The rowStartPoint argument is used within gp:calculate-Draw-TileRow as the starting point for the centers of the circles in the row. To compensate for the initial forward shifting of the rowStartPoint during the drawing of the first row that is, the first cycle through the while loop , you will want to shift rowStartPoint slightly in the opposite direction.
The aim is to avoid the appearance of a large margin of empty space between the path boundary and the first row. Half the TileRadius is a sufficient amount by which to move the point.
This can be achieved by using polar to project rowStartPoint along a vector oriented degrees from the PathAngle. If you think about it, this places the point temporarily outside the path boundary. In essence, there is setq wrapped around an append wrapped around the call to gp:calculate-Draw-TileRow. The Object ID points to the tile object in the drawing. You are drawing the tiles row by row, so the function returns the Object IDs of one row at a time. This is the offset toggle, which determines whether the row being drawn should begin with a circle centered on the path or offset from the path.
The pseudo-code for this algorithm follows: Set the offset amount to the following: If the offset is currently zero, set it to the offset distance; Otherwise, set it back to zero. Drawing the Tiles in a Row Now that you have the logic for drawing the path, the next step is to figure out how to draw the tiles in each row.
In the following diagram, there are two cases shown: a row where the offset from the center of the path is equal to 0. Take a look at the diagram, then read the pseudo-code that follows. Set up variables for StartPoint, angp90, angm90, and so on.
Comment: Begin by drawing the circles in the angp90 direction. Set TileCenterPt to the next tile space increment in the angp90 direction. Set TileCenterPt to the next tile space increment in the angm90 direction. End While Return the list of circles. Contact developer for assistance. Contact the developer for assistance.
Remember the specification to allow users to draw the tiles circles using either ActiveX, the entmake function, or the command function? Here are the three functions as they will be defined in gpdraw. The second function draws a circle using entmake. It returns an entity name converted into an ActiveX object.
The third function draws a circle using command. It also returns an entity name converted into an ActiveX object. Do you notice a difference in the speed with which the path is drawn with each method? Match the parentheses in your code. Find and complete a function name. Obtain online help for a function. You finished the lesson by building code that draws the tiles in the garden path. You now have a program that meets the requirements established at the very beginning of this tutorial.
But if you are up to it, there are two more lessons in this tutorial that demonstrate the use of reactor functions and other advanced features of the VLISP environment. In this lesson, you will learn about reactors and how to attach them to drawing events and entities. Reactors allow your application to be notified by AutoCAD when particular events occur. For example, if a user moves an. You can program this to trigger additional operations, such as moving other entities associated with the one the user moved, or perhaps updating a text tag that records revision information on the altered drawing feature.
In effect, it is like setting up your application with a pager and telling AutoCAD to beep the application when something happens. Reactor Basics A reactor is an object you attach to the drawing editor, or to specific entities within a drawing. Extending the metaphor of the pager, the reactor object is an automatic dialer that knows how to call your pager when something significant happens. The pager within your application is an AutoLISP function called by the reactor; such a function is known as a callback function.
NOTE The complexity of the application code and the level of expertise required for these final two lessons is much higher than Lessons 1 through 5. There is a great deal of information presented, but it is not all explained at the same level of detail as in the previous lessons.
Consider this just a first taste of some of the very powerful but more technically difficult features of VLISP. Each reactor type responds to one or more AutoCAD events. Reactors are grouped into the following categories: Editor Reactors. With the exception of editor reactors, there is one type of reactor for each reactor category. Within the reactor categories, there are many specific events to which you can attach a reactor. AutoCAD allows users to perform many different kinds of actions, and it is up to you to determine the actions that you are interested in.
Designing Reactors for the Garden Path To implement reactor functionality in the garden path application, start by handling just a few events, rather than trying to cover all possible user actions. When a corner point vertex of the garden path boundary is repositioned, redraw the path so that the outline remains rectilinear. In addition, redraw the tiles based on the new size and shape. When the garden path boundary is erased, erase the tiles as well. Planning the Callback Functions For each reactor event, you must plan the function that will be invoked when the event occurs.
The following pseudo-code outlines the logical sequence of events that should occur when users drag one of the polyline vertices to a new location: Defun gp:outline-changed Erase the tiles. Determine how the boundary changed. Straighten up the boundary. Redraw new tiles. End function. There is a complication, though. When the user begins dragging the outline of a polyline vertex, AutoCAD notifies your application by issuing a :vlr-modified event.
However, at this point the user has just begun dragging one of the polyline vertices. If you immediately invoke the gp:outline-changed function, you will interrupt the action that the user is in the midst of. You would not know where the new vertex location will be, because the user has not yet selected its position. And finally, AutoCAD will not allow your function to modify the polyline object while the user is still. AutoCAD has the polyline object open for modification, and leaves it open until the user finishes repositioning the object.
You need to change your approach. Here is the updated logic: When the user begins repositioning a polyline vertex, Invoke the gp:outline-changed function Defun gp:outline-changed. Set a global variable that stores a pointer to the polyline being modified by the user. End function When the command completes, Invoke the gp:command-ended function Defun gp:command-ended.
Erase the tiles. Get information on the previous polyline vertex locations. Get information on the new polyline vertex locations. Redefine the polyline straighten it up. Redraw the tiles. When a user completes modifying a path outline, AutoCAD notifies your application by issuing a :vlr-commandEnded event, if you have established an editor reactor.
The use of a global variable to identify the polyline the user changed is necessary because there is no continuity between the gp:outline-changed and gp:command-ended functions. In your application, both functions are invoked and executed independently of one another. The global variable stores important information set up in one function and accessed in the other.
Now consider what to do if the user erases the garden path boundary. The ultimate objective is to erase all the tiles. The following pseudo-code outlines the logic: When the user begins to erase the boundary, Invoke the gp:outline-erased function Defun gp:outline-erased.
Set a global variable that stores a pointer to the reactor attached to the polyline currently being erased. End function When the erase is completed, Invoke the gp:command-ended function Defun gp:command-ended. Erase the tiles that belonged to the now-deleted polyline. Planning for Multiple Reactors Users may have several garden paths on the screen, and may be erasing more than one.
You need to plan for this possibility. The reactor associated with an entity is an object reactor. If there are several entities in the drawing, there may also be several object reactors, one for each entity. A specific editing event, such as the erase command, can trigger many callbacks, depending on how many of the selected entities have reactors attached.
Editor reactors, on the other hand, are singular in nature. Your application should only attach a single :vlr-commandEnded event reactor. The event sequence for both modifications—changing a vertex location and erasing a polyline—ends up with actions that need to be performed within the gp:command-ended function. Determine which set of actions to perform for each condition. The following pseudo-code outlines the logic: Defun gp:command-ended 2nd version Retrieve the pointer to the polyline from a global variable.
Conditional: If the polyline has been modified then: Erase the tiles. End conditional expression. If the polyline has been erased then: Erase the tiles. End Conditional End function. Attaching the Reactors The next step in planning a reactor-based application is to determine how and when to attach reactors. You need to attach two object reactors for the polyline border of any garden path one to respond to a modification event, the other to respond to erasure , and one editor reactor to alert your application when users complete their modification to the polyline.
Object reactors are attached to entities, while editor reactors are registered with AutoCAD. There is another consideration to account for.
To recalculate the polyline outline—return it to a rectilinear shape—after the user modifies it, you must know what the vertex configuration was before the modification.
This information cannot be determined once the polyline has been modified. By that time you can only retrieve information on what the new configuration is. So how do you solve this? You could keep this information in a global variable, but there is a major problem with that idea.
Users can draw as many garden paths as they want, and every new path would require a new global variable. This would get very messy. When the user first draws a path boundary, you attach a reactor to the boundary, along with the data you need to save.
Attach an object reactor to the polyline using these parameters: A pointer to the polyline just drawn, A list of data that you want the reactor to record, A list of the specific polyline object events to be tracked, along with the LISP callback functions to be invoked. End of the object reactor setup. Attach editor reactor to the drawing editor using the following parameters: Any data you want attached to the reactor in this case,none A list of the specific editor reactor events to be tracked, along with the LISP callback functions to be invoked.
End of the editor reactor setup. To add reactor creation logic to C:GPath 1 Replace your version of gpmain. By counting up the number of points using the ;; length function , we can print out the results of how many ;; tiles were drawn. This will be stored in the reactor data for the reactor attached to the boundary polyline. For this exercise we will use all arguments associated with vlr-object-reactor. These reactor functions will execute only if the polyline in PolylineName is modified or erased.
This is where to place the object to be associated with the reactor. In this case, it is the vlaObject stored in PolylineName. This is extremely important!!!!!!!!! This tutorial shows all modified code in boldface. Adding Reactor Callback Functions The reactor callback functions add a substantial amount of code to your application. This code is provided for you in the Lesson6 directory. To add the reactor callback functions to your program 1 Copy the gpreact. Move any files, if necessary, then press OK.
Read through the comments in the file to help you understand what it is doing. Note that all the callback functions are stubbed out; the only functionality they perform is to display alert messages when they are fired. The last function in the file is so important it deserves a heading of its own. When you design an application that relies on them, you could very well spend a great deal of time crashing your program and possibly crashing AutoCAD as well.
It helps to have a tool available to remove all the reactors you have added, if necessary. The gpreact. Instead, it makes a call to the CleanReactors function. Add this function to your utils. It can be used during debugging, as ; ;;; well as cleaning up any open reactors before ; ;;; a drawing is closed.
Test Driving Your Reactors By now, you should have all the necessary pieces in place to use some live reactors. To test the reactor code 1 Load all the source code from your project.
Press the Load Source Files button in the gpath project window. The program will draw a garden path for you, just as you were able to in Lesson 5. Move a polyline vertex. Pick the polyline and turn on its grips, then drag a vertex to a new location. Stretch the polyline. Examine the messages that appear. You are watching the behind-the-scenes activities of a powerful capability.
Use the Gpath6 project in that directory. Examining Reactor Behavior in Detail With a stack of scrap paper, start tracing the reactor events within the application. Here is an example of the kinds of things you should track: Command: erase Object: Polyline border Reactor sequence 1.
Type in erase command 2. Select objects: pick a polyline 4. Hit Enter object selection complete 5. This exercise will give you a good understanding of what is happening behind the scenes. You designed a plan for adding reactors to the garden path application, and added some of the code your program will need to implement the plan.
Reactors can add a great deal of functionality to an application, but remember—the more powerful your programs can be, the harder they can crash. Another thing to keep in mind is that the way your application is designed, the reactor functionality is not persistent from one drawing session to the next.
If you save a drawing that contains a garden path hooked up to reactors, the reactors will not be there the next time you open the drawing.
Process reactor-based applications. In Lesson 7, you will add functionality to this knowledge and create a garden. After testing your application and determining that it works. You should consider this part of the tutorial as the advanced topics section. Planning the Overall Reactor Process You need to define several new functions in this lesson.
Rather than present you with details on all aspects of the new code, this lesson presents an overview and points out the concepts behind the code. At the end of the lesson, you will have all the source code necessary to create a garden path application identical to the sample program you ran in Lesson 1. NOTE When you are in the midst of developing and debugging reactor-based applications, there is always the potential of leaving AutoCAD in an unstable state. This can be caused by several situations, such as failing to remove a reactor from deleted entities.
Begin by loading the project as it existed at the end of Lesson 6. You also need to consider how to handle the global variables in your program. Often, it is desirable to have globals retain a value throughout an AutoCAD drawing session.
In the case of reactors, however, this is not the case. To illustrate this, imagine a user of your garden path application has drawn several garden paths in a single drawing. After doing this, the user erases them, first one at a time, then two at a time, and so on, until all but one path is erased. The polyline is not actually removed until the gp:command-ended event fires.
The first time the user deletes a polyline, things work just as you would expect. In gp:outline-erased, you store a pointer to the reactor. When gp:command-ended fires, you remove the tiles associated with the polyline to which the reactor is attached, and all is well. Then, the user decides to erase two paths. As a result, your application will get two calls to gp:outline-erased, one for each polyline about to be erased.
There are two potential problems you must anticipate:. You can then accumulate several reactor pointers corresponding to the number of paths the user is erasing within a single erase command. This is necessary so that the global is not storing reactor pointers from the previous erase command.
If you do not reinitialize the global variable or use the correct data structure in this case, a list , you will get unexpected behavior. In the case of reactors, unexpected behavior can be fatal to your AutoCAD session. Here is the chain of events that needs to occur for users to erase two garden paths with a single erase command. Initiate the erase command.
This triggers the gp:command-will-start function. Select two polylines; your application is not yet notified. Your application gets a callback to gp:outline-erased for one of the polylines. Your application gets a callback to gp:outline-erased for the second of the polylines. Using StarBatch you can automate Au. Source: sourceforge. It is a full-included, interpretive programming language that you can use to call AutoCAD directions, framework factors, and discourse boxes.
Source: freecadtipsandtricks. Visual Lisp Autocad 2. Autocad Lisp Download 3. Autocad Lisp Download.
0コメント