The AutoLisp Tutorial With DCL
The AutoLisp Tutorial With DCL
Here is the basic order for things to happen inside the AutoLisp file:
(defun C:MyProgram()
(defun myFunction1()
saveVars
load_dialog
new_dialog
DCL file
start_list
add_list
end_list
start_list
add_list
end_list
set_tile
mode_tile
necessary)
unload_dialog
I've found the hardest thing to get a grip on is laying out the dialog box. Please take
a look at the rows and columns section if you need help with laying out a dialog box.
For now let's look at the basics. We will cover these items first: button, row, column,
boxed_row, and boxed_column.
Okay and Cancel Buttons - The DCL code for a these buttons look like this:
: button {
key = "accept";
assigned to this button)
label = " Okay ";
button.
is_default = true;
presses the enter key.
}
: button {
key = "cancel";
the button.)
label = " Cancel ";
is_default = false;
Rows and Columns designate areas to lay your controls on. [Controls are list
boxes, edit boxes, buttons, etc. ].
Here is the DCL code for a column:
: column {
}
Here is the DCL code for a row:
: row {
}
Simple right?
Let's turn the above into Boxed Rows and Boxed Columns. Here is the code for
a boxed_column with two buttons:
: boxed_column {
: button {
key = "accept";
label = " Okay ";
is_default = true;
}
: button {
key = "cancel";
label = " Cancel ";
is_default = false;
is_cancel = true;
}
}
Now we know the difference between a row and a boxed_row. We also know that
controls inside a column get stacked on top of each other [ vertical ] and controls
inside a row are next to each other [ horizontal ].
Important: You should never ever attempt to build a dialog box without a cancel
button.
Overview
Let's take a look at the entire code for the dialog box above, including the LSP file:
DCL FILE NAMED: DCL_TEST.DCL
DCL_TEST.lsp
DCL_TEST : dialog {
: boxed_row {
: button {
key = "accept";
(defun C:DCL_TEST()
(if(not(setq dcl_id (load_dialog "DCL_TEST.dcl")))
(progn
(alert "The DCL file could not be loaded.")
(exit)
)
(progn
(if (not (new_dialog "DCL_TEST" dcl_id))
(progn
(alert "The definition could not be found inside the
DCL file")
(exit)
)
(progn
(action_tile "cancel" "(done_dialog 1)")
(action_tile "accept" "(done_dialog 2)")
(setq ddiag(start_dialog))
(unload_dialog dcl_id)
(if (= ddiag 1)
(princ "\n \n ...DCL_TEST Cancelled. \n ")
)
(if (= ddiag 2)
(alert "You pressed the OKAY button!")
)
)
: button {
key = "cancel";
label = " Cancel
";
is_default =
false;
is_cancel = true;
}
}
)
)
)
(princ)
)
AutoLISP
Let's take a look at the AutoLisp part of this simple program.
First we defined our program:
(defun C:DCL_TEST()
The second thing was to load the DCL file from disk. Insert a path if necessary, but I
always liked to use the autocad search path to find the file. Notice the dcl_id variable
used. We will need this later on. This identifies the file opened.
;;;--- Load the dialog file from disk into memory
(setq dcl_id (load_dialog "DCL_TEST.dcl"))
You can improve this with a little error checking:
(if(not (setq dcl_id (load_dialog "DCL_TEST.dcl")))
(progn
(alert "The file could not be loaded.")
(exit)
Since a DCL file can contain multiple dialog box definitions, [ I'll show you an
example later on. ] we need to specify which dialog box we want to load. This is
taken care of in the next statement. Notice the name matches the definition inside the
DCL file.
;;;--- See if the DCL definition is found inside the DCL file
(new_dialog "DCL_TEST" dcl_id)
You can inprove this with a little error checking:
The only problem with the above method is if the DCL file fails to load into memory
you will get an alert stating the file did not load. That's not a problem, but you will
also get an alert saying the Definition could not be found. We don't want both
popping up. So, change the above to be nested, like this:
;;;--- Try to load the DCL file from disk into memory
(if(not(setq dcl_id (load_dialog "DCL_TEST.dcl")))
(progn
(alert "The DCL file could not be loaded.")
(exit)
)
;;;--- Else, the DCL file was loaded into memory
(progn
;;;--- Try to load the definition inside the DCL file
(if (not (new_dialog "DCL_TEST" dcl_id))
(progn
(alert "The definition could not be found inside the DCL file")
(exit)
)
;;;--- Else, the definition was loaded, we are ready to roll
(progn
;;;--- Put action keys here
)
)
Next, we define our action keys. These tell the program what to do whenever a user presses a
button, selects an item in a list, etc. Notice the two action keys. "cancel" and "accept" . These
match the keys in the DCL file. I made these names up. You can name them whatever you want
as long as it is not a name used by AutoCAD and it only appears once in each DCL definition.
You can't have two controls with the same key, the program would get confused. So would I!!!
Whenever the user presses the cancel key, the done_dialog statement returns the value of 1 the
start_dialog statement and closes the dialog box. Upon pressing the Okay button, [ key =
accept ], the done_dialog program returns the value of 2 to the start_dialog statement and closes
the dialog box. That's it. Nothing else to add, except you could have just about anything in here,
including instructions to execute a function [ I'll demonstrate that later. ]
;;;--- If an action event occurs, do this function
(action_tile "cancel" "(done_dialog 1)")
(action_tile "accept" "(done_dialog 2)")
Finally, the big step. Everything is defined, let's display the dialog box and set up the variable
to hold the value returned from the done_dialog statement.
;;;--- Display the dialog box
(setq ddiag(start_dialog))
The program halts here until the dialog box is issued a "done_dialog" call. In the mean time
the user is interacting with the action keys. When the user presses a button the program kills the
dialog box with the unload_dialog call. Notice the dcl_id passed as a parameter. You could have
more than one dialog file open at one time. So, the unload_dialog function needs to know which
one to unload.
;;;--- Unload the dialog box from memory
(unload_dialog dcl_id)
Finally the dialog box is gone. What next? Find out which button the user pressed?
Exactly! Remember the done_dialog was setup to return either 1 or 2. The start_dailog
statement set this value to the variable ddiag. We will use that now to determine which button
was pressed.
// The edit_box
(defun C:EXAMPLE()
;;;--- Try to load the DCL file from disk into memory
(if(not(setq dcl_id (load_dialog "DCL_TEST.dcl")))
(progn
(alert "The DCL file could not be loaded.")
(exit)
)
;;;--- Else, the DCL file was loaded into memory
(progn
;;;--- Try to load the definition inside the DCL file
)
)
)
;;;--- Suppress the last echo for a clean exit
(princ)
)
Screen Shot:
If you could not follow some of the autolisp functions, you can ignore them for now
or read the Autolisp Tutorial.
This is the model. Very little will change from this setup. You may add some
controls to the DCL file which in turn will add Action calls and influence the number
of lines inside the saveVars routine. The only other thing that will change is inside the
OKAY button function. [ When ddiag = 2 ]. You will have to tell the program what
to do when all of the information is gathered. We will cover these later.
Back
Layout thoughts: I will place the buttons in a column, (stacked on top of each
other). Then I'll put the Close button at the bottom on a row of it's own. So...I'll need
something like this:
: column {
: boxed_column {
: button {
// Put code for button 1 here
}
: button { ]
// Put code for button 2 here
}
: button { ]
// Put code for button 3 here
}
}
: boxed_row {
: button {
Let's copy in the code for the header and all of the controls above. I'll show them in
red. Notice the key names and labels had to be changed.
SAMPLE1 : dialog {
label = "Sample Dialog Box Routine - Part 1";
: column {
: boxed_column {
: button {
key = "but1";
label = "Button 1";
is_default = false;
}
: button {
key = "but2";
label = "Button 2";
is_default = false;
}
: button {
key = "but3";
label = "Button 3";
is_default = false;
}
}
: boxed_row {
: button {
key = "cancel";
label = "Close";
is_default = true;
is_cancel = true;
}
}
}
}
Right click and copy the above. Open NotePad and paste it. Save the file as
SAMPLE1.DCL Be sure to change the "Save as Type" drop down box to "All
Files" before saving it or it will put a ".txt" extension on the file name. Save this
file somewhere in the AutoCAD search path.
Next we will get a copy of the AutoLisp model and revise it. All new code is shown
in red.
(defun C:SAMPLE1()
;;;--- Load the dcl file from disk to memory
(if(not(setq dcl_id (load_dialog "SAMPLE1.dcl")))
(progn
(alert "The DCL file could not be loaded.")
(exit)
)
(progn
;;;--- Load the DCL definition inside the DCL file
(if (not (new_dialog "SAMPLE1" dcl_id))
(progn
(alert "The SAMPLE1 definition could not be found inside
the DCL file!")
(exit)
)
;;;--- Else, the definition was loaded
(progn
;;;--- If an action event occurs, do this function
(action_tile "cancel" "(done_dialog)")
;;;--- Display the dialog box
(start_dialog)
;;;--- Unload the dialog box
(unload_dialog dcl_id)
)
)
)
)
;;;--- Suppress the last echo for a clean exit
(princ)
I removed several lines from the model. I took out the part that checked to see if we
hit the Cancel or Okay buttons. We don't need either in this program. I also removed
the action tile for the okay button, removed "setq ddiag" from the start_dialog
statement, and removed the value to return from the done_dialog statement.
Right click and copy the above. Open NotePad and paste it. Save the file as
SAMPLE1.LSP Be sure to change the "Save as Type" drop down box to "All
Files" before saving it or it will put a ".txt" extension on the file name. Save this
file somewhere in the AutoCAD search path.
Let's load the program and see what the DCL file looks like. On the command line
type this:
Command: (load "sample1") and press enter
You should see this
C:Sample1
Command:
Now type Sample1 and press enter. If everything went according to plan you should
see this on your screen:
The buttons do not work yet. Except for the close button. It should work fine. We
need to add the function to print three different messages when the user presses each
button. Let's send a parameter to the function to decide which message to display. If
the parameter equals 1 we will print the first message. If 2 then print the second
message. If 3 print the third message. Something like this:
(defun doButton(a)
(cond
((= a 1)(alert "Button 1 was pressed!"))
((= a 2)(alert "Button 2 was pressed!"))
((= a 3)(alert "Button 3 was pressed!"))
)
)
Now we need to add the action calls for each of the buttons:
(action_tile "but1" "(doButton 1)")
(action_tile "but2" "(doButton 2)")
(action_tile "but3" "(doButton 3)")
This will send a parameter of 1,2, or 3 to the doButton function depending on which
button is pressed.
Let's add the doButton function and the action calls to the autolisp program. It
should look like this:
(defun doButton(a)
(cond
((= a 1)(alert "Button 1 was pressed!"))
((= a 2)(alert "Button 2 was pressed!"))
((= a 3)(alert "Button 3 was pressed!"))
)
)
(defun C:SAMPLE1()
;;;--- Load the dcl file from disk into memory
(if(not(setq dcl_id (load_dialog "SAMPLE1.dcl")))
(progn
(alert "The DCL file could not be loaded.")
(exit)
)
;;;--- Else, the file was loaded
(progn
;;;--- Load the dialog definition inside the DCL file
(if (not (new_dialog "SAMPLE1" dcl_id))
(progn
(alert "The SAMPLE1 definition could not be found in the
DCL file!")
(exit)
)
;;;--- Else, the definition was loaded
(progn
;;;--- If an
(action_tile
(action_tile
(action_tile
(action_tile
When you get your program tested and everything is working, move the blue line
above, [ (defun C:SAMPLE1() ] all the way to the top of the file. This will make all
of your variables local and will reset them all to nil when the program ends.
That's it. We're done.
Back
Layout thoughts: I will place the edit boxes in a column, (stacked on top of each
other). Then I'll put the Okay and Cancel buttons at the bottom in a row. So...I'll need
something like this:
: column {
: boxed_column {
: edit_box {
// Put code for edit_box 1 here
}
: edit_box {
// Put code for edit_box 3 here
}
}
: boxed_row {
: button {
// Put code for the Okay button here
}
: button {
// Put code for the Cancel button here
}
}
}
Let's copy in the code for the header and all of the controls above. I'll show them in
red. Notice the key names and labels had to be changed.
SAMPLE2 : dialog {
label = "Sample Dialog Box Routine - Part 2";
: column {
: boxed_column {
: edit_box {
key = "username";
label = "Enter your Name:";
edit_width = 15;
value = "";
initial_focus = true;
}
: edit_box {
key = "userage";
label = "Enter your Age:";
edit_width = 15;
value = "";
}
}
: boxed_row {
: button {
key = "accept";
label = " Okay ";
is_default = true;
}
: button {
key = "cancel";
Next we will get a copy of the AutoLisp model and revise it. All new code is shown
in red.
(defun C:SAMPLE2()
;;;--- Load the dcl file from disk into memory
(if(not(setq dcl_id (load_dialog "SAMPLE2.dcl")))
(progn
(alert "The DCL file could not be loaded!")
(exit)
)
;;;--- Else, the dcl file was loaded into memory
(progn
;;;--- Load the definition inside the DCL file
(if (not(new_dialog "SAMPLE2" dcl_id))
(progn
(alert "The SAMPLE2 definition could not be loaded!")
(exit)
)
;;;--- Else, the definition was loaded
(progn
;;;--- If an action event occurs, do this function
(action_tile "accept" "(saveVars)(done_dialog 2)")
(action_tile "cancel" "(done_dialog 1)")
Right click and copy the above. Open NotePad and paste it. Save the file as
SAMPLE2.LSP Be sure to change the "Save as Type" drop down box to "All
Files" before saving it or it will put a ".txt" extension on the file name. Save this
file somewhere in the AutoCAD search path.
Let's load the program and see what the DCL file looks like. On the command line
type this:
Command: (load "sample2") and press enter
You should see this
C:Sample2
Command:
Now type Sample2 and press enter. If everything went according to plan you should
see this on your screen:
Looking good so far. We need to add the SaveVars function to save the strings in
the edit boxes when the Okay button is pressed. Look at the blue text in the
Sample2.lsp program above.
The edit box for the name needs to be a string. Dialog boxes return strings, so we do
not need to modify it. All we have to do is use the get_tile function.
(setq userName(get_tile "username"))
The edit box for Age needs to be an integer. We will have to modify the get_tile
results by using the ATOI function. This function converts a string to an integer.
(setq userAge( atoi (get_tile "userage")))
(princ)
)
Last item. We need to replace the line in the program: (princ "\n The user
pressed Okay!") with something to modify and display the userName and
userAge data. Let's do something simple. We will find out how many days old this
person is.
;;;--- If the user pressed the Okay button
(if(= ddiag 2)
(progn
;;;--- Multiply the users age x 365 to get the number of
days.
(setq userAge(* userAge 365))
;;;--- Display the results
(alert (strcat userName " is " (itoa userAge) " days
old."))
)
)
Add the above to the file, save it and test it out. Everything working okay?
When you get your program tested and everything is working, move the blue line
above, [ (defun C:SAMPLE2() ] all the way to the top of the file. This will make all
of your variables local and will reset them all to nil when the program ends.
That's it. We're done.
Back
Layout thoughts: I will place the list boxes in a row, (side by side). Then I'll put
the Okay and Cancel buttons in a row at the bottom of the dialog box. So...I'll need
something like this:
: column {
: boxed_row {
: list_box {
// Put code for list_box 1 here
}
: list_box {
// Put code for list_box 2 here
}
}
: boxed_row {
: button {
// Put code for the Okay button here
}
: button {
// Put code for the Cancel button here
}
}
}
Let's copy in the code for the header and all of the controls above from the "Controls"
section of this tutorial. I'll show them in red. Notice the key names and labels had to
be changed.
SAMPLE3 : dialog {
label = "Sample Dialog Box Routine - Part 3";
: column {
: boxed_row {
: list_box {
label ="Choose Item";
key = "mylist1";
height = 15;
width = 25;
multiple_select = false;
fixed_width_font = true;
value = "";
}
: list_box {
label ="Choose Items";
key = "mylist2";
height = 15;
width = 25;
multiple_select = true;
fixed_width_font = true;
value = "";
}
}
: boxed_row {
: button {
key = "accept";
label = " Okay ";
is_default = true;
}
: button {
key = "cancel";
label = " Cancel ";
is_default = false;
is_cancel = true;
}
}
}
}
Right click and copy the above. Open NotePad and paste it. Save the file as
SAMPLE3.DCL Be sure to change the "Save as Type" drop down box to "All
Files" before saving it or it will put a ".txt" extension on the file name. Save this
file somewhere in the AutoCAD search path.
Next we will get a copy of the AutoLisp model and revise it. All new code is shown
in red.
(defun C:SAMPLE3()
;;;--- Load the dcl file from disk into memory
(if(not(setq dcl_id (load_dialog "SAMPLE3.dcl")))
(progn
(alert "The DCL file could not be loaded!")
(exit)
)
;;;--- Else, the DCL file was loaded
(progn
;;;--- Load the dialog definition inside the DCL file
(if (not(new_dialog "SAMPLE3" dcl_id))
(progn
(alert "The SAMPLE3.DCL file could not be loaded!")
(exit)
)
;;;--- Else, the definition was loaded
(progn
;;;--- If an action event occurs, do this function
(action_tile "accept" "(saveVars)(done_dialog 2)")
(action_tile "cancel" "(done_dialog 1)")
;;;--- Display the dialog box
(setq ddiag(start_dialog))
Right click and copy the above. Open NotePad and paste it. Save the file as
SAMPLE3.LSP Be sure to change the "Save as Type" drop down box to "All
Files" before saving it or it will put a ".txt" extension on the file name. Save this
file somewhere in the AutoCAD search path.
Let's load the program and see what the DCL file looks like. On the command line
type this:
Command: (load "sample3") and press enter
You should see this
C:Sample3
Command:
Now type Sample3 and press enter. If everything went according to plan you should
see this on your screen:
Looks good but, there is nothing to choose. Let's add some data to the list boxes.
We will need two list. We will call the list for the first list box myList1 and the
second myList2.
(setq myList1(list "Electrical" "Structural" "Plumbing"
"Foundation"))
(setq myList2(list "Plastic" "Steel" "Aluminum" "Concrete"))
Alrighty then, we have our list built. All we have to do is put them in the dialog box.
We will use the start_list, add_list, and end_list functions. Start_list tells DCL which
list_box we are going to edit. The identification is made by using the list_box KEY.
The first list has a key of "mylist1" and the second has a key of "mylist2". So the
start_list function would look like this:
(start_list "mylist1" 3) ; The 3 means we want to delete the old
contents and start new.
Next we use the add_list function to tell DCL which list to put in the list_box. We
use the mapcar function to apply add_list to each member in the list. Our list for the
first list_box is named myList1. So...
Let's add all of this to the AutoLisp program and see what it looks like.
(defun C:SAMPLE3()
(setq myList1(list "Electrical" "Structural" "Plumbing" "Foundation"))
(setq myList2(list "Plastic" "Steel" "Aluminum" "Concrete"))
;;;--- Load the dcl file from disk into memory
(if(not(setq dcl_id (load_dialog "SAMPLE3.dcl")))
(progn
(alert "The DCL file could not be loaded!")
(exit)
)
;;;--- Else, the DCL file was loaded
(progn
;;;--- Load the dialog definition if it is not already
loaded
(if (not(new_dialog "SAMPLE3" dcl_id))
(progn
(alert "The SAMPLE3 definition could not be loaded!")
(exit)
)
;;;--- Else, the definition was loaded
(progn
(start_list "mylist1" 3)
(mapcar 'add_list myList1)
(end_list)
(start_list "mylist2" 3)
(mapcar 'add_list myList2)
(end_list)
;;;--- If an action event occurs, do this function
(action_tile "accept" "(saveVars)(done_dialog 2)")
(action_tile "cancel" "(done_dialog 1)")
;;;--- Display the dialog box
(setq ddiag(start_dialog))
;;;--- Unload the dialog box
(unload_dialog dcl_id)
;;;--- If the user pressed the Cancel button
(if(= ddiag 1)
(princ "\n Sample3 cancelled!")
)
;;;--- If the user pressed the Okay button
(if(= ddiag 2)
(progn
(princ "\n The user pressed Okay!")
)
)
)
)
)
)
;;;--- Suppress the last echo for a clean exit
(princ)
)
Notice the location of the red lines. We create the list before loading the dialog box.
We add the list to the dialog box after it is loaded with new_dialog and before the
action_tile statements. This is the order you should use.
Looking good so far. We need to add the SaveVars function to save the selected
items from the list boxes when the Okay button is pressed. Look at the blue text in
the Sample3.lsp program above.
Let's steal the saveVars routine from the list_box control on the "List and how to
handle them" page of this tutorial and modify it. I'll show the modifications in red.
Wow! That was easy. Wait a minute, we have two list boxes. We will have to create
a function out of this or simply copy this and do it twice. For now, let's just do it
twice.
(defun C:SAMPLE3()
(if(= ddiag 2)
(progn
(princ "\n The user pressed Okay!")
)
)
)
)
)
)
;;;--- Suppress the last echo for a clean exit
(princ)
)
Last item. We need to replace the line in the program: (princ "\n The user
pressed Okay!") with something to modify and display the selected items. Let's
do something simple. We will tell the user what was selected out of each list..
;;;--- If the user pressed the Okay button
(if(= ddiag 2)
(progn
;;;--- Inform the user of his selection from the first list
(princ (strcat "\n You chose " (car retList) " from the
first list box."))
;;;--- Inform the user of his selections from the second
list
(princ "\n Your choice(s) from the second list box :")
(foreach a retList2
(princ "\n ")
(princ a)
)
)
)
Add the above to the file, save it and test it out. Everything working okay?
When you get your program tested and everything is working, move the blue line
above, [ (defun C:SAMPLE3() ] all the way to the top of the file. This will make all
of your variables local and will reset them all to nil when the program ends.
That's it. We're done.
Back
Layout thoughts: I will place the popup_list in a row, (side by side). Then I'll put
the Okay and Cancel buttons in a row at the bottom of the dialog box. So...I'll need
something like this:
: column {
: boxed_row {
: popup_list {
// Put code for popup_list 1 here
}
: popup_list {
// Put code for popup_list 2 here
}
}
: boxed_row {
: button {
// Put code for the Okay button here
}
: button {
// Put code for the Cancel button here
}
}
}
Let's copy in the code for the header and all of the controls above from the "Controls"
section of this tutorial. I'll show them in red. Notice the key names and labels had to
be changed.
SAMPLE4 : dialog {
label = "Sample Dialog Box Routine - Part 4";
: column {
: boxed_row {
: popup_list {
key = "mylist1";
label = "Select Item";
fixed_width_font = true;
width = 30;
value = "";
}
: popup_list {
key = "mylist2";
label = "Select Item";
fixed_width_font = true;
width = 30;
value = "";
}
}
: boxed_row {
: button {
key = "accept";
label = " Okay ";
is_default = true;
}
: button {
key = "cancel";
label = " Cancel ";
is_default = false;
is_cancel = true;
}
}
}
}
Right click and copy the above. Open NotePad and paste it. Save the file as
SAMPLE4.DCL Be sure to change the "Save as Type" drop down box to "All
Files" before saving it or it will put a ".txt" extension on the file name. Save this
file somewhere in the AutoCAD search path.
Next we will get a copy of the AutoLisp model and revise it. All new code is shown
in red.
(defun C:SAMPLE4()
;;;--- Load the dcl file from disk into memory
(if(not(setq dcl_id (load_dialog "SAMPLE4.dcl")))
(progn
(alert "The DCL file could not be loaded!")
(exit)
)
;;;--- Else, the DCL file was loaded
(progn
;;;--- Load the definition inside the DCL file
(if (not(new_dialog "SAMPLE4" dcl_id))
(progn
(alert "The SAMPLE4.DCL file could not be loaded!")
(exit)
)
;;;--- Else, the definition was loaded
(progn
;;;--- If an action event occurs, do this function
(action_tile "accept" "(saveVars)(done_dialog 2)")
(action_tile "cancel" "(done_dialog 1)")
;;;--- Display the dialog box
(setq ddiag(start_dialog))
;;;--- Unload the dialog box
(unload_dialog dcl_id)
;;;--- If the user pressed the Cancel button
(if(= ddiag 1)
(princ "\n Sample4 cancelled!")
)
;;;--- If the user pressed the Okay button
(if(= ddiag 2)
(progn
(princ "\n The user pressed Okay!")
)
)
)
)
)
)
;;;--- Suppress the last echo for a clean exit
(princ)
)
Right click and copy the above. Open NotePad and paste it. Save the file as
SAMPLE4.LSP Be sure to change the "Save as Type" drop down box to "All
Files" before saving it or it will put a ".txt" extension on the file name. Save this
file somewhere in the AutoCAD search path.
Let's load the program and see what the DCL file looks like. On the command line
type this:
Command: (load "sample4") and press enter
You should see this
C:Sample4
Command:
Now type Sample4 and press enter. If everything went according to plan you should
see this on your screen:
Looks good but, there is nothing to choose. Let's add some data to the popup list
boxes. We will need two list. We will call the list for the first popup list box myList1
and the second myList2.
(setq myList1(list "Electrical" "Structural" "Plumbing"
"Foundation"))
(setq myList2(list "Plastic" "Steel" "Aluminum" "Concrete"))
Alrighty then, we have our list built. All we have to do is put them in the dialog box.
We will use the start_list, add_list, and end_list functions. Start_list tells DCL which
popup list box we are going to edit. The identification is made by using the popup list
box KEY. The first popup list box has a key of "mylist1" and the second has a key of
"mylist2". So the start_list function would look like this:
(start_list "mylist1" 3) ; The 3 means we want to delete the old
contents and start new.
Next we use the add_list function to tell DCL which list to put in the popup list box.
We use the mapcar function to apply add_list to each member in the list. Our list for
the first popup list box is named myList1. So...
(mapcar 'add_list myList1)
Finally we use the end_list function to tell DCL to display the new contents because
we are through editing the popup list box.
(end_list)
To look at it all together:
(start_list "mylist1" 3)
(mapcar 'add_list myList1)
(end_list)
(start_list "mylist2" 3)
(mapcar 'add_list myList2)
(end_list)
Let's add all of this to the AutoLisp program and see what it looks like.
(defun C:SAMPLE4()
(setq myList1(list "Electrical" "Structural" "Plumbing" "Foundation"))
(setq myList2(list "Plastic" "Steel" "Aluminum" "Concrete"))
;;;--- Load the dcl file from disk into memory
(if(not(setq dcl_id (load_dialog "SAMPLE4.dcl")))
(progn
(alert "The DCL file could not be loaded!")
(exit)
)
;;;--- Else, the DCL file was loaded
(progn
;;;--- Load the definition inside the DCL file
(if (not(new_dialog "SAMPLE4" dcl_id))
(progn
(alert "The SAMPLE4.DCL file could not be loaded!")
(exit)
)
;;;--- Else, the definition was loaded
(progn
(start_list "mylist1" 3)
(mapcar 'add_list myList1)
(end_list)
(start_list "mylist2" 3)
(mapcar 'add_list myList2)
(end_list)
;;;--- If an action event occurs, do this function
(action_tile "accept" "(saveVars)(done_dialog 2)")
(action_tile "cancel" "(done_dialog 1)")
;;;--- Display the dialog box
(setq ddiag(start_dialog))
;;;--- Unload the dialog box
(unload_dialog dcl_id)
;;;--- If the user pressed the Cancel button
(if(= ddiag 1)
(princ "\n Sample4 cancelled!")
)
Notice the location of the red lines. We create the list before loading the dialog box.
We add the list to the dialog box after it is loaded with new_dialog and before the
action_tile statements. This is the order you should use.
Looking good so far. We need to add the SaveVars function to save the selected
items from the popup list boxes when the Okay button is pressed. Look at the blue
text in the Sample4.lsp program above.
Let's steal the saveVars routine from the popup list box control on the "Saving data
from the dialog box" page of this tutorial and modify it. I'll show the modifications in
red.
(defun saveVars()
;;;--- Get the selected item from the first list
(setq sStr1(get_tile "mylist1"))
;;;--- Make sure something was selected...
(if(= sStr1 "")>
(setq myItem1 nil)
(setq myItem1 (nth (atoi sStr1) myList1))
)
)
Wait a minute, we have two pop_up list boxes. We will have to create a function out
of this or simply copy this and do it twice. For now, let's just do it twice.
(defun saveVars()
;;;--- Get the selected item from the first list
(setq sStr1(get_tile "mylist1"))
;;;--- Make sure something was selected...
(if(= sStr1 "")>
(setq myItem1 "Nothing")
(setq myItem1 (nth (atoi sStr1) myList1))
)
;;;--- Get the selected item from the second list
(setq sStr2(get_tile "mylist2"))
;;;--- Make sure something was selected...
(if(= sStr2 "")>
(setq myItem2 "Nothing")
(setq myItem2 (nth (atoi sStr2) myList2))
)
)
(defun C:SAMPLE4()
(setq myList1(list "Electrical" "Structural" "Plumbing" "Foundation"))
(setq myList2(list "Plastic" "Steel" "Aluminum" "Concrete"))
;;;--- Load the dcl file from disk into memory
(if(not(setq dcl_id (load_dialog "SAMPLE4.dcl")))
(progn
(alert "The DCL file could not be loaded!")
(exit)
)
;;;--- Else, the DCL file was loaded
(progn
;;;--- Load the definition inside the DCL file
(start_list "mylist1" 3)
(mapcar 'add_list myList1)
(end_list)
(start_list "mylist2" 3)
(mapcar 'add_list myList2)
(end_list)
;;;--- If an action event occurs, do this function
(action_tile "accept" "(saveVars)(done_dialog 2)")
(action_tile "cancel" "(done_dialog 1)")
;;;--- Display the dialog box
(setq ddiag(start_dialog))
;;;--- Unload the dialog box
(unload_dialog dcl_id)
;;;--- If the user pressed the Cancel button
(if(= ddiag 1)
(princ "\n Sample4 cancelled!")
)
;;;--- If the user pressed the Okay button
(if(= ddiag 2)
(progn
(princ "\n The user pressed Okay!")
)
)
)
)
)
)
;;;--- Suppress the last echo for a clean exit
(princ)
)
Last item. We need to replace the line in the program: (princ "\n The user
pressed Okay!") with something to modify and display the selected items. Let's
do something simple. We will tell the user what was selected out of each popup list..
;;;--- If the user pressed the Okay button
(if(= ddiag 2)
(progn
;;;--- Inform the user of his selection from the first list
(princ (strcat "\n You chose " myItem1 " from the first
popup list box."))
;;;--- Inform the user of his selections from the second
list
(princ (strcat "\n You chose " myItem2 " from the second
popup list box."))
)
)
Add the above to the file, save it and test it out. Everything working okay?
When you get your program tested and everything is working, move the blue line
above, [ (defun C:SAMPLE4() ] all the way to the top of the file. This will make all
of your variables local and will reset them all to nil when the program ends.
That's it. We're done.
Back
: column {
: radio_column {
// Put code for radio_column here
: radio_column {
// Put code for radio_button 1 here
}
: radio_button {
// Put code for radio_button 2 here
}
: radio_button {
// Put code for radio_button 3 here
}
: radio_button {
// Put code for radio_button 4 here
}
}
: boxed_row {
: button {
// Put code for the Okay button here
}
: button {
// Put code for the Cancel button here
}
}
}
Let's copy in the code for the header and all of the controls above from the "Controls"
section of this tutorial. I'll show them in red. Notice the key names and labels had to
be changed.
SAMPLE5 : dialog {
label = "Sample Dialog Box Routine - Part 5";
: column {
: radio_column {
key = "mychoice";
: radio_button {
key = "but1";
label = "Apples";
}
: radio_button {
key = "but2";
label = "Oranges";
}
: radio_button {
key = "but3";
label = "Bananas";
}
: radio_button {
key = "but4";
label = "Lemons";
}
}
: boxed_row {
: button {
key = "accept";
label = " Okay ";
is_default = true;
}
: button {
key = "cancel";
label = " Cancel ";
is_default = false;
is_cancel = true;
}
}
}
}
Right click and copy the above. Open NotePad and paste it. Save the file as
SAMPLE5.DCL Be sure to change the "Save as Type" drop down box to "All
Files" before saving it or it will put a ".txt" extension on the file name. Save this
file somewhere in the AutoCAD search path.
Next we will get a copy of the AutoLisp model and revise it. All new code is shown
in red.
(defun C:SAMPLE5()
;;;--- Load the dcl file from disk into memory
(if(not(setq dcl_id (load_dialog "SAMPLE5.dcl")))
(progn
(alert "The DCL file could not be loaded!")
(exit)
)
;;;--- Else, the DCL file was loaded
(progn
;;;--- Load the definition inside the DCL file
(if (not(new_dialog "SAMPLE5" dcl_id))
(progn
(alert "The SAMPLE5 definition could not be loaded!")
(exit)
)
;;;--- Else, the definition was loaded
(progn
;;;--- If an action event occurs, do this function
(action_tile "accept" "(saveVars)(done_dialog 2)")
(action_tile "cancel" "(done_dialog 1)")
;;;--- Display the dialog box
(setq ddiag(start_dialog))
;;;--- Unload the dialog box
(unload_dialog dcl_id)
;;;--- If the user pressed the Cancel button
(if(= ddiag 1)
(princ "\n Sample5 cancelled!")
)
;;;--- If the user pressed the Okay button
(if(= ddiag 2)
(progn
(princ "\n The user pressed Okay!")
)
)
)
)
)
)
;;;--- Suppress the last echo for a clean exit
(princ)
)
Right click and copy the above. Open NotePad and paste it. Save the file as
SAMPLE5.LSP Be sure to change the "Save as Type" drop down box to "All
Files" before saving it or it will put a ".txt" extension on the file name. Save this
file somewhere in the AutoCAD search path.
Let's load the program and see what the DCL file looks like. On the command line
type this:
Command: (load "sample5") and press enter
You should see this
C:Sample5
Command:
Now type Sample5 and press enter. If everything went according to plan you should
see this on your screen:
That doesn't look very good does it? Let's change the boxed_row into
a boxed_column in our DCL file. (See the blue text in the DCL file above) Make the
changes then Save the Sample5.DCL file. No need to load the autolisp program
again, it's loaded. Just run the Sample5 program again. Now it should look like this:
It still doesn't look right. It's our label "Sample Dialog Box Routine - Part 5" that is
causing the problem. Let's shorten it to "SDBR - Part 5" and try it again:
Looks better!
Looking good so far. We need to add the SaveVars function to save the selected
items from the radio_column when the Okay button is pressed. Look at the blue text
in the Sample5.lsp program above.
Let's steal the saveVars routine from the radio_column control on the "Saving data
from the dialog box" page of this tutorial and modify it. I'll show the modifications in
red.
We can do this two different ways. We can check each radio_button to find out
which one is on or we can check the entire column of radio_buttons by getting the
value of the radio_column.
First method: Checking the Radio_Column:
(defun saveVars()
;;;--- Get the key of the choice made
;;;
[ returns "but1" "but2" "but3" or "but4" whichever is
selected.]
(setq myChoice(get_tile "mychoice"))
)
Second method: Checking each Radio_Button:
(defun saveVars()
;;;--- Get the value of each item
(setq choice1(atoi(get_tile "but1")))
(setq choice2(atoi(get_tile "but2")))
(setq choice3(atoi(get_tile "but3")))
(setq choice4(atoi(get_tile "but4")))
; 0 = not chosen
; 0 = not chosen
; 0 = not chosen
; 0 = not chosen
1 = chosen
1 = chosen
1 = chosen
1 = chosen
So...Which one do we use? For this tutorial, let's use both. Why not?
(defun saveVars()
;;;--- Get the key of the choice made
;;;
[ returns "but1" "but2" "but3" or "but4" whichever is
selected.]
(setq myChoice(get_tile "mychoice"))
;;;--- Get the value of each item
(setq choice1(atoi(get_tile "but1")))
(setq choice2(atoi(get_tile "but2")))
(setq choice3(atoi(get_tile "but3")))
(setq choice4(atoi(get_tile "but4")))
)
; 0 = not chosen
; 0 = not chosen
; 0 = not chosen
; 0 = not chosen
1 = chosen
1 = chosen
1 = chosen
1 = chosen
Add this to the original Sample5.lsp program and we should have something that
looks like this:
(defun saveVars()
;;;--- Get the key of the choice made
;;;
[ returns "but1" "but2" "but3" or "but4" whichever is
selected.]
(setq myChoice(get_tile "mychoice"))
;;;--- Get the value of each item
(setq choice1(atoi(get_tile "but1")))
(setq choice2(atoi(get_tile "but2")))
(setq choice3(atoi(get_tile "but3")))
(setq choice4(atoi(get_tile "but4")))
; 0 = not chosen
; 0 = not chosen
; 0 = not chosen
; 0 = not chosen
1 = chosen
1 = chosen
1 = chosen
1 = chosen
)
(defun C:SAMPLE5()
;;;--- Load the dcl file from disk into memory
(if(not(setq dcl_id (load_dialog "SAMPLE5.dcl")))
(progn
(alert "The DCL file could not be loaded!")
(exit)
)
;;;--- Else, the DCL file was loaded
(progn
;;;--- Load the definition inside the DCL file
(if (not (new_dialog "SAMPLE5" dcl_id))
(progn
(alert "The DCL definition could not be loaded!")
(exit)
)
;;;--- Else, the definition was loaded
(progn
;;;--- If an action event occurs, do this function
(action_tile "accept" "(saveVars)(done_dialog 2)")
(action_tile "cancel" "(done_dialog 1)")
;;;--- Display the dialog box
(setq ddiag(start_dialog))
;;;--- Unload the dialog box
(unload_dialog dcl_id)
;;;--- If the user pressed the Cancel button
(if(= ddiag 1)
(princ "\n Sample5 cancelled!")
)
;;;--- If the user pressed the Okay button
(if(= ddiag 2)
(progn
(princ "\n The user pressed Okay!")
)
)
)
)
)
)
;;;--- Suppress the last echo for a clean exit
(princ)
)
Last item. We need to replace the line in the program: (princ "\n The user
pressed Okay!") with something to display the selected item.
;;;--- If the user pressed the Okay button
(if(= ddiag 2)
(progn
;;;--- Inform the user of his selection using the
radio_column data
(princ "\n Using Radio_column data...You chose ")
(cond
((= myChoice "but1")(princ "Apples!"))
((= myChoice "but2")(princ "Oranges!"))
((= myChoice "but3")(princ "Bananas!"))
((= myChoice "but4")(princ "Lemons!"))
)
Add the above to the autolisp file, save it and test it out. Everything working okay?
When you get your program tested and everything is working, move the blue line
above, [ (defun C:SAMPLE5() ] all the way to the top of the file. This will make all
of your variables local and will reset them all to nil when the program ends.
Layout thoughts: I will place the text control on the top of the box. Then I'll put
the toggles in a column, (stacked on top of each other). Last, I'll put the Cancel button
at the bottom of the dialog box. So...I'll need something like this:
: column {
: column {
: text {
// Put code for
}
}
: boxed_column {
: toggle {
// Put code for
}
: toggle {
// Put code for
}
: toggle {
// Put code for
text here
toggle 1 here
toggle 2 here
toggle 3 here
}
: toggle {
// Put code for toggle 4 here
}
}
: boxed_row {
: button {
// Put code for the Cancel button here
}
}
}
Let's copy in the code for the header and all of the controls above from the "Controls"
section of this tutorial. I'll show the changes that needed to be made in red. Notice
the key names and labels had to be changed.
SAMPLE6 : dialog {
label = "Sample Dialog Box Routine - Part 6";
: column {
: column {
: text {
key = "text1";
value = "Nothing selected.";
}
}
: boxed_column {
label = "Choose your lucky charms:";
: toggle {
key = "tog1";
label = "Hearts";
value = "0";
}
: toggle {
key = "tog2";
label = "Moons";
value = "0";
}
: toggle {
key = "tog3";
label = "Stars";
value = "0";
}
: toggle {
key = "tog4";
label = "Clovers";
value = "0";
}
}
: boxed_row {
: button {
key = "cancel";
label = "Cancel";
is_default = true;
is_cancel = true;
}
}
}
Right click and copy the above. Open NotePad and paste it. Save the file as
SAMPLE6.DCL Be sure to change the "Save as Type" drop down box to "All
Files" before saving it or it will put a ".txt" extension on the file name. Save this
file somewhere in the AutoCAD search path.
Next we will get a copy of the AutoLisp model and revise it. All new code is shown
in red.
(defun C:SAMPLE6()
;;;--- Load the dcl file from disk into memory
(if(not(setq dcl_id (load_dialog "SAMPLE6.dcl")))
(progn
(alert "The DCL file could not be loaded!")
(exit)
)
;;;--- Else, the DCL file was loaded
(progn
;;;--- Load the dialog definition inside the DCL file
(if (not (new_dialog "SAMPLE6" dcl_id))
(progn
(alert "The SAMPLE6 definition could not be loaded!")
(exit)
)
;;;--- Else, the definition was loaded
(progn
;;;--- If an action event occurs, do this function
(action_tile "accept" "(saveVars)(done_dialog 2)")
(action_tile "cancel" "(done_dialog 1)")
;;;--- Display the dialog box
(setq ddiag(start_dialog))
;;;--- Unload the dialog box
(unload_dialog dcl_id)
;;;--- If the user pressed the Cancel button
(if(= ddiag 1)
(princ "\n Sample6 cancelled!")
)
;;;--- If the user pressed the Okay button
(if(= ddiag 2)
(progn
(princ "\n The user pressed Okay!")
)
)
)
)
)
)
;;;--- Suppress the last echo for a clean exit
(princ)
)
Remove everything listed in orange above. We do not need an Okay button. Thus
we do not need to check to see if the user pressed Okay or Cancel. We also do not
need the SaveVars routine in this program. Remove the orange items so your
program looks like the one below.
(defun C:SAMPLE6()
;;;--- Load the dcl file from disk into memory
Right click and copy the above. Open NotePad and paste it. Save the file as
SAMPLE6.LSP Be sure to change the "Save as Type" drop down box to "All
Files" before saving it or it will put a ".txt" extension on the file name. Save this
file somewhere in the AutoCAD search path.
Let's load the program and see what the DCL file looks like. On the command line
type this:
Command: (load "sample6") and press enter
You should see this
C:Sample6
Command:
Now type Sample6 and press enter. If everything went according to plan you should
see this on your screen:
Doesn't look right. The dialog box is too wide. It's our label "Sample Dialog Box
Routine - Part 6" that is causing the problem. I would shorten it but, my text control
will need the room if everything is selected. I'll have to display "Hearts Moons Stars
Clovers" all on one line. I'll leave it the way it is.
Notice you can select and deselect items without a problem but the text control
doesn't change. We need to add the action_tiles and function to accomplish this.
First let's write a routine to check each toggle and build a string representing all of
the selected items.
(defun chkToggle()
(setq
(setq
(setq
(setq
tog1(atoi(get_tile
tog2(atoi(get_tile
tog3(atoi(get_tile
tog4(atoi(get_tile
(setq
(if(=
(if(=
(if(=
(if(=
myStr "")
tog1 1)(setq
tog2 1)(setq
tog3 1)(setq
tog4 1)(setq
"tog1")))
"tog2")))
"tog3")))
"tog4")))
myStr(strcat
myStr(strcat
myStr(strcat
myStr(strcat
; 0 = not chosen
; 0 = not chosen
; 0 = not chosen
; 0 = not chosen
myStr
myStr
myStr
myStr
"
"
"
"
1 = chosen
1 = chosen
1 = chosen
1 = chosen
Hearts")))
Moons")))
Stars")))
Clovers")))
I used the get_tile function to get the value of each toggle. I used the atoi function
to convert that data from a string to an integer. (I could have left it a string and
checked to see if tog1 equalled "1" instead of the number 1.) I set the
variable myStr to an empty string and then appended all the checked toggle labels to
it. I then changed the value of the text control by using the set_tile function.
Add this to the top of your autolisp program and save it.
The last step is to add the action calls to the AutoLisp program. We need one action
call per toggle switch. Each action call should run the chkToggle function we just
created.
(action_tile
(action_tile
(action_tile
(action_tile
"tog1"
"tog2"
"tog3"
"tog4"
"(chkToggle)")
"(chkToggle)")
"(chkToggle)")
"(chkToggle)")
Let's add this to the AutoLisp program. I'll show the new chkToggle function and
the action calls in red. It should look like this:
(defun chkToggle()
(setq
(setq
(setq
(setq
tog1(atoi(get_tile
tog2(atoi(get_tile
tog3(atoi(get_tile
tog4(atoi(get_tile
(setq
(if(=
(if(=
(if(=
(if(=
myStr "")
tog1 1)(setq
tog2 1)(setq
tog3 1)(setq
tog4 1)(setq
"tog1")))
"tog2")))
"tog3")))
"tog4")))
myStr(strcat
myStr(strcat
myStr(strcat
myStr(strcat
; 0 = not chosen
; 0 = not chosen
; 0 = not chosen
; 0 = not chosen
myStr
myStr
myStr
myStr
"
"
"
"
1 = chosen
1 = chosen
1 = chosen
1 = chosen
Hearts")))
Moons")))
Stars")))
Clovers")))
"tog1" "(chkToggle)")
"tog2" "(chkToggle)")
"tog3" "(chkToggle)")
"tog4" "(chkToggle)")
"cancel" "(done_dialog 1)")
When you get your program tested and everything is working, move the blue line
above, [ (defun C:SAMPLE6() ] all the way to the top of the file. This will make all
of your variables local and will reset them all to nil when the program ends.
That's it. We're done.
Back
Layout thoughts: The list will need to have several layers showing so the user
won't have to scroll forever. So, it will probably be the tallest item on the dialog
box. I'll put it in a column by itself. I'll try to fit the rest of the items in a column
beside it. Then I'll put the Okay and Cancel buttons at the bottom in a row. So...I'll
need something like this:
: column {
: row {
: boxed_column {
: radio_column {
: radio_button {
// Put code for radio button 1 here [ Circle ]
}
: radio_button {
// Put code for radio button 2 here [ Polygon ]
}
}
: popup_list {
[ Save Settings ]
}
}
: row {
: list_box {
// Put code for list here [ Layer Names ]
}
}
}
: row {
: button {
// Put code for button 1 here [ Okay ]
}
: button {
// Put code for button 2 here [ Cancel ]
}
}
}
Let's copy in the code for the header and all of the controls above. I'll show them in
red. Notice the key names and labels had to be changed.
SAMPLE7 : dialog {
label = "Sample Dialog Box Routine - Part 7";
: column {
: row {
: boxed_column {
: radio_column {
key = "radios";
: radio_button {
label = "Draw Circle";
key = "drawcir";
value = "1";
}
: radio_button {
label = "Draw Polygon";
key = "drawpol";
value = "0";
}
}
: popup_list {
key = "numsides";
label = "Number of Sides";
width = 25;
fixed_width_font = true;
}
: toggle {
key = "saveset";
label = "Save settings";
}
}
: row {
: list_box {
label ="Select Layer";
key = "layerList";
height = 5;
width = 15;
multiple_select = false;
fixed_width_font = true;
value = "";
}
}
}
: row {
: button {
key = "accept";
label = " Okay ";
is_default = true;
}
: button {
key = "cancel";
label = " Cancel ";
is_default = false;
is_cancel = true;
}
}
}
}
Right click and copy the above. Open NotePad and paste it. Save the file as
SAMPLE.DCL Be sure to change the "Save as Type" drop down box to "All
Files" before saving it or it will put a ".txt" extension on the file name. Save this
file somewhere in the AutoCAD search path.
Next we will get a copy of the AutoLisp model and revise it. All new code is shown
in red.
(defun C:SAMPLE7()
;;;--- Load the dcl file from disk into memory
(if(not(setq dcl_id (load_dialog "SAMPLE7.dcl")))
(progn
(alert "The DCL file could not be loaded!")
(exit)
)
;;;--- Else, the DCL file was loaded
(progn
;;;--- Load the definition inside the DCL file
(if (not (new_dialog "SAMPLE7" dcl_id))
(progn
(alert "The SAMPLE7 definition could not be loaded!")
(exit)
)
;;;--- Else, the definition was loaded
(progn
;;;--- If an action event occurs, do this function
(action_tile "cancel" "(done_dialog 1)")
(action_tile "accept" "(saveVars)(done_dialog 2)")
;;;--- Display the dialog box
(setq ddiag(start_dialog))
;;;--- Unload the dialog box
(unload_dialog dcl_id)
;;;--- If the cancel button was pressed - display
message
(if (= ddiag 1)
(princ "\n \n ...SAMPLE7 Cancelled. \n ")
)
;;;--- If the "Okay" button was pressed
(if (= ddiag 2)
(princ "\n \n ...SAMPLE7 Complete!")
)
)
)
)
)
;;;--- Suppress the last echo for a clean exit
(princ)
)
Right click and copy the above. Open NotePad and paste it. Save the file as
SAMPLE7.LSP Be sure to change the "Save as Type" drop down box to "All
Files" before saving it or it will put a ".txt" extension on the file name. Save this
file somewhere in the AutoCAD search path.
Let's load the program and see what the DCL file looks like. On the command line
type this:
Command: (load "sample7") and press enter
You should see this
C:Sample7
Command:
Now type Sample and press enter. If everything went according to plan you should
see this on your screen:
Notice there are no items in either list. We haven't added that part yet. Also notice
the Draw Circle is selected. We did that in the DCL file. We set the value of that
radio_button to "1". We did not set the value of the toggle, so the default is
unchecked.
If you push the Cancel button the program will exit normally. If you press the Okay
button an error will occur because we have not defined the saveVars routine.
We have two things left to do. First we need to build the list for the popup_list
control and the list_box control. Then we need to add the list to the dialog box.
Instead of building a function to get all of the layer names into a list, let's just build
the list manually to keep things simple. Okay...you talked me into it. I'll do it both
ways and you can use the one you want. I'm going to use the short version for this
tutorial.
Long way:
;;;--- Set up a list to hold the layer names
(setq layerList(list))
;;;--- Get the first layer name in the drawing
(setq layr(tblnext "LAYER" T))
;;;--- Add the layer name to the list
(setq layerList(append layerList (list(cdr(assoc 2 layr)))))
;;;--- Step though the layer table to get all layers
(while (setq layr(tblnext "LAYER"))
;;;--- Save each layer name in the list
Short Way:
(setq layerList(list "0" "DIM" "HIDDEN" "STR" "TX" "WELD"))
We need to add these lines to our autolisp program. Add it just below the new_dialog
call and above the action_tile statements.
We now need to upload the list into the dialog box. So put these lines just below the
lines you just added.
;;;--- Add the layer names to the dialog box
(start_list "layerlist" 3)
(mapcar 'add_list layerList)
(end_list)
;;;--- Add the number of sides to the dialog box
(start_list "numsides" 3)
(mapcar 'add_list numSides)
(end_list)
When you are done it should look like this:
(defun C:SAMPLE7()
;;;--- Load the dcl file from disk into memory
(if(not(setq dcl_id (load_dialog "SAMPLE7.dcl")))
(progn
(alert "The DCL file could not be loaded!")
(exit)
)
;;;--- Else, the DCL file was loaded
(progn
;;;--- Load the definition inside the DCL file
(if (not (new_dialog "SAMPLE7" dcl_id))
(progn
(alert "The SAMPLE7 definition could not be loaded!")
(exit)
)
;;;--- Else, the definition was loaded
(progn
Next, let's build the SaveVars routine. We will do this by starting with the saveVars
routine in the AutoLisp Model, then copy and paste from the "Save Data from Dialog
Box" section of this tutorial. We will then modify the names to match the key names
in the DCL file. I also changed a variable name to numStr to be used later to set the
default settings. More on that later. I'll show you the changes I made in red:
(defun saveVars()
(setq radios(get_tile "radios"))
;;;--- Get the number of sides selected from the list
(setq numStr(get_tile "numsides"))
(if(= numStr "")
(setq numSides nil)
(setq numSides(nth (atoi numStr) numSides))
)
;;;--- See if the user wants to save the settings
(setq saveSet(atoi(get_tile "saveset")))
;;;--- Get the selected item from the layer list
(setq sStr(get_tile "layerlist"))
;;;--- If the index of the selected item is not "" then
something was selected
(if(/= sStr "")
(progn
;;;--- Something is selected, so convert from string to
integer
(setq sIndex(atoi sStr))
Note: Since we did not specify a default value for the list_box, layerName will be set
to nil if the user does not select a layer from the list before hitting the Okay button.
Save, Load, and Run. Check the values after pressing the Okay button by typing an
exclamation point and then the variable name on the command line. Examples: To
get the layer name type !layerName and press enter. To get the value of the toggle
type !saveSet and press enter.
The only work left on the dialog box is to disable the "Number of Sides" popup_list
when a circle is selected. Let's add two action_tiles on both of the radio_buttons.
;;;--- If an action event occurs, do this function
(action_tile "drawcir" "(toggleRadio 1)")
(action_tile "drawpol" "(toggleRadio 2)")
This will send a parameter of 1 to the toggleRadio function if the Circle is selected.
It will send a parameter of 2 to the toggleRadio function if the Polygon is selected.
What the hell is a toggleRadio function?
We have to create it and put it in our AutoLisp program. Like this:
(defun toggleRadio(a)
;disable
;enable
)
)
Since our default for the radio buttons is to draw a circle, the numSides popup_list
should be disabled before the dialog box starts. So just before the action_tile
statements we need to add this line:
(mode_tile "numsides" 1)
Copy, Save, and Run.
The numSides popup_list is disabled when the circle is selected. Enabled when
polygon is selected.
Here is the AutoLisp program after the lines above were added:
(defun saveVars()
(setq radios(get_tile "radios"))
(defun C:SAMPLE7()
;;;--- Load the dcl file from disk into memory
(if(not(setq dcl_id (load_dialog "SAMPLE7.dcl")))
(progn
(alert "The DCL file could not be loaded!")
(exit)
)
;;;--- Else, the DCL file was loaded
(progn
;;;--- Load the definition inside the DCL file
(if (not (new_dialog "SAMPLE7" dcl_id))
(progn
(alert "The SAMPLE7 definition could not be loaded!")
(exit)
)
;;;--- Else, the definition was loaded
(progn
(setq layerList(list "0" "DIM" "HIDDEN" "STR" "TX" "WELD"))
(setq numSides(list "4" "6" "8" "12" "16"))
;;;--- Add the layer names to the dialog box
(start_list "layerlist" 3)
(mapcar 'add_list layerList)
(end_list)
;;;--- Add the number of sides to the dialog box
(start_list "numsides" 3)
(mapcar 'add_list numSides)
(end_list)
(mode_tile "numsides" 1)
;;;--- If an
(action_tile
(action_tile
(action_tile
(action_tile
Now the only thing remaining is to do something when the user presses the okay
button. We have all of the dialog box data stored in variable names....
Variable Name
Action Key
radios
Radio_Column
"radios"
numSides
Popup_List
"numsides"
saveSet
Toggle
"saveset"
Integer [ 0 or 1 ]
layerName
List
"layerlist"
So now all we have to do is write the AutoLisp code inside the "Okay button was
pressed" IF statement. (Where the blue line is above.)
Now we will replace the blue line above: (princ "\n \n ...SAMPLE
Complete!") with new code.
First, let's go ahead and change the layer.
(setq oldLay(getvar "clayer"))
(setvar "clayer" layerName)
Add the above to your program and save it. Test it out. Everything working okay?
And finally all we have left is the code for the default settings. Since everything in
the dialog box is a string, why don't we save all of the data as strings. Lucky for us,
AutoDesk included 15 setvars for us to store data in. USERR1 thru USERR5 is used
to store real numbers. USERI1 thru USERI5 is used to store integers. USERS1 thru
USERS5 are used to store strings. We will use the system variables USERS1 thru
USERS4 to save our data since we are saving the data as strings. All of these setvars
are stored inside the drawing file. They will be there everytime you open your
drawing. How convenient! So let's get to it.
The first variable to store is RADIOS and it is already a string. So....
(setvar "USERS1" radios)
The second variable to store is NUMSIDES and it is an integer representing the
number of sides the polygon should have. I want to store the index of the selected
item in the list not the actual number of sides. We saved the index as a variable
named NUMSTR when we ran the saveVars routine. So...
(setvar "USERS2" numStr)
The third variable to save is SAVESET. It is stored as an integer. We will have to
convert it to a string to save it.
(setvar "USERS3" (itoa saveSet))
The fourth and final variable to save is LAYERNAME. It is stored as a string. I
want to save the index of the selected item. We saved that earlier with the saveVars
routine in a variable named sSTR.
The last thing we have to do is check for the default settings and load them if they
exist.
(defun saveVars()
(setq radios(get_tile "radios"))
;;;--- Get the number of sides selected from the list
(setq numStr(get_tile "numsides"))
(if(= numStr "")
(setq numSides nil)
(setq numSides(nth (atoi numStr) numSides))
)
;;;--- See if the user wants to save the settings
(setq saveSet(atoi(get_tile "saveset")))
;;;--- Get the selected item from the layer list
(setq sStr(get_tile "layerlist"))
;;;--- If the index of the selected item is not "" then
something was selected
(if(/= sStr "")
(progn
;;;--- Something is selected, so convert from string to
integer
(setq sIndex(atoi sStr))
;;;--- And get the selected item from the list
(setq layerName(nth sIndex layerList))
)
;;;--- Else, nothing is selected
(progn
;;;--- Set the index number to -1
(setq sIndex -1)
;;;--- And set the name of the selected item to nil
(setq layerName nil)
)
)
)
(defun toggleRadio(a)
;if circle is selected
(if(= a 1)
(mode_tile "numsides" 1) ;disable
;else
(mode_tile "numsides" 0) ;enable
)
)
(defun C:SAMPLE7()
;;;--- Load the dcl file from disk into memory
(if(not(setq dcl_id (load_dialog "SAMPLE7.dcl")))
(progn
(alert "The DCL file could not be loaded!")
(exit)
)
;;;--- Else, the DCL file was loaded
(progn
;;;--- Load the definition inside the DCL file
(if (not (new_dialog "SAMPLE7" dcl_id))
(progn
(alert "The SAMPLE7 definition could not be loaded!")
(exit)
)
;;;--- Else, the definition was loaded
(progn
(setq layerList(list "0" "DIM" "HIDDEN" "STR" "TX" "WELD"))
(setq numSides(list "4" "6" "8" "12" "16"))
;;;--- Add the layer names to the dialog box
(start_list "layerlist" 3)
(mapcar 'add_list layerList)
(end_list)
;;;--- Add the number of sides to the dialog box
(start_list "numsides" 3)
(mapcar 'add_list numSides)
(end_list)
"USERS1"
"USERS2"
"USERS3"
"USERS4"
radios)
numStr)
(itoa saveSet))
sSTR)
)
)
)
)
)
)
)
)
;;;--- Suppress the last echo for a clean exit
(princ)
)
When you get your program tested and everything is working, move the blue line
above, [ (defun C:SAMPLE7() ] all the way to the top of the file. This will make all
of your variables local and will reset them all to nil when the program ends.
That's it. We're done.
Back
is on
value = "0";
}
}
}
: row {
: boxed_row {
: button {
key = "accept";
label = " Okay ";
is_default = true;
}
: button {
key = "cancel";
label = " Cancel ";
is_default = false;
is_cancel = true;
}
}
}
}
}
(defun C:EXAMPLE()
;;;--- I need to build a list of data
(setq myList(list "1" "2" "3" "4" "5" "6" "7" "8"))
;;;--- Load the dcl file from disk into memory
(if(not(setq dcl_id (load_dialog "EXAMPLE.dcl")))
(progn
(alert "The DCL file could not be loaded!")
(exit)
)
;;;--- Else, the DCL file was loaded into memory
(progn
;;;--- Load the dialog definition inside the DCL file
(if (not (new_dialog "EXAMPLE" dcl_id))
(progn
(alert "The DCL definition could not be found inside
the DCL file!")
(exit)
)
;;;--- Else, the dialog definition loaded
(progn
;;;--- Here, I add the data to the list_box control
;;;
I do this after the new_dialog call and before
the action_tiles.
(start_list "mylist" 3)
(mapcar 'add_list myList)
(end_list)
;;;--- Notice the "mylist" is the action key associated
with the DCL file and
;;;
the myList is the variable for the list built
above.
;;;--- If an action event occurs, do this function
(action_tile "cancel" "(done_dialog 1)")
(action_tile "accept" "(saveVars)(done_dialog 2)")
;;;--- Display the dialog box
(setq ddiag(start_dialog))
;;;--- If the cancel button was pressed - display
message
(if (= ddiag 1)
(princ "\n \n ...EXAMPLE Cancelled. \n ")
)
;;;--- If the "Okay" button was pressed
(if (= ddiag 2)
;;;--- Here, I decide what to do with my data
;;;
I'm going to print each selected item on the
command line.
(foreach a retList
(princ "\n")(princ a)
)
)
)
)
)
)
;;;--- Suppress the last echo for a clean exit
(princ)
)
So, in order to display a list in a dialog box, you must first build the list. Then use
the start_list, add_list, and end_list functions just after the new_dialog call and before
the action_tiles. This is the same for both a list_box and a popup_list.
Back
"key"
"value")
"Key" - The name of the key you defined with the control inside the DCL file.
"Value"- The new value for the control.
Edit_box
o (set_tile "mybox" "Jeff") Displays Jeff in the edit
box.
o (set_tile "mybox" "4'-3 1/2") Displays 4'-3 1/2 in
the edit box.
List_box
o (set_tile "mylist" "0") Selects the first item in the
list.
o (set_tile "mylist" "5") Selects the sixth item in the
list.
PopUp_List
o (set_tile "mylist" "0") Selects the first item in the
list.
o (set_tile "mylist" "5") Selects the sixth item in the
list.
o (set_tile "mylist" "")
Toggle
o (set_tile "mytog" "0") Removes the check from the
box.
o (set_tile "mytog" "1") Checks the box.
Radio_Button
o (set_tile "myradio1" "1") Moves the selection to the
first radio button.
o (set_tile "myradio2" "1") Moves the selection to the
2nd radio button.
Use Set_Tile after the new_dialog and before the action_tiles. Set_Tile can also be
used as a function while the dialog box is displayed.
"key"
value)
"Key" - The name of the key you defined with the control inside the DCL file.
Value- The new value for the control.
0 = Enabled 1 = Disabled
That is all there is to set_tile and mode_tile. We will used them later on in the
tutorial so you can see them in action.
Back
"key"
"action")
"Key" - The name of the key you defined with the control inside the DCL file.
"Action"- The action you want taken when the action event is fired.
a variable or run a function.
Examples:
Let's take for example, you have a button named "test" and you want to set the
variable named myTEST to 1 if the user presses the button:
(action_tile
"test"
Notice the key is in quotes and the setq function is in quotes. This is standard
procedure for the action_tile statement. Next let's say you have the same thing except
you want to run a function named "saveVars" when the user presses the test button.
(action_tile
"test"
"(saveVars)")
"test"
That is about all there is to an action_tile. Remember, anything with a key can have
an action call.
Back
Slide_image
For this tutorial we will concentrate on the Slide_Image function. Everyone knows
how to create a slide right? The MSLIDE command. Okay. We will assume our
image is ready.
Let's look at the DCL Image definition and the AutoLisp functions required to
display the image.
DCL - You must supply either the width and height or one of these plus an
aspect_ratio.
: image {
key = "sld";
height = 30;
width = 30;
color = 0;
is_enabled = false;
is_tab_stop = false;
}
AutoLisp
;;;--- First we need a slide name
(setq mySlideName "c:/acad/myslide.sld")
;;;--- Second we need the key to the image control
(setq myKey "sld")
;;;--- Next we send the slide name and the key to the update
function
(upDateImage mySlideName myKey)
; NOTE: Notice mySlideName becomes sldName and myKey becomes key
when passed
;
as parameters to the upDateImage function.
;;;--- Function to update the slide
(defun upDateImage(sldName key)
;;;--- Get the width of the slide
(setq width (dimx_tile key))
;;;--- Get the height of the slide
(setq height (dimy_tile key))
;;;--- Start the slide definition
(start_image key)
;;;--- Wipe out the background
(fill_image 0 0 width height 0)
;;;--- Put the slide in the image area
(slide_image 0 0 width height sldName)
;;;--- Finish the slide definition
(end_image)
)
This function can be used over and over to display any slide image in an image
control. Use the upDateImage function after the new_dialog call and before the
action_tile statements. You can also use this function while the dialog box is
displayed in one of your action calls.
Back
Let's
Stuffing
There are three parts to a control with an action call back statement.
1. The DCL definition
2. The action call in the AutoLisp file.
3. The code inside the SaveVars routine.
In each of the following controls I will show you all three parts so we know how to put it all
together later. Although, all of the parts are important, try to focus on the SaveVars routine.
Edit_box
List_Box_Single_Selection - List_Box_Multiple_Selection
- Popup_List
Radio_Column
Radio_Row
Toggle -
Ok_Cancel
Edit_Box
: edit_box {
key = "edbox";
label = "Bolt Circle Diameter:";
1
edit_width = 8;
value = "10";
}
No Action call required. We will get the data the user typed when we use the SaveVars
routine. But, if your deadset about doing something when the user types in the edit box,
here you go:
(action_tile "edbox" "(doThisFunction)")
(defun saveVars()
(defun saveVars()
3
(setq edBox(distof(get_tile
"edbox")))
NOTE: Notice I used the key name as the variable to store the data in. You will
find this method makes it easier to keep things straight. DCL is case sensitive
so, I never capitalize key names, only autolisp variable names if they are made up
of more than one word. Like: thisIsMyVariable.
List_Box
: list_box {
key = "mylist";
label = "Available Choices";
multiple_select = "FALSE";
width = 40;
height = 20;
fixed_width_font = true;
value = "";
}
No Action call required. We will get the selected item when we use the SaveVars
routine. But, sometimes you need to change things in the dialog box if the user makes a
selection, so:
(action_tile "edbox" "(doThisFunction)")
(defun saveVars()
Notes:
1. This should only be used when single selection is required. This will not work on
multiple selection.
2. This is assuming there is a list of items called myList.
List_Box
Multiple Choice
: list_box {
key = "mylist";
label = "Available Choices";
multiple_select = "TRUE";
width = 40;
height = 20;
fixed_width_font = false;
alignment ]
value = "4";
}
No Action call required. We will get the selected items when we use the SaveVars
routine. But, sometimes you need to change things in the dialog box if the user makes a
selection, so:
(action_tile "mylist" "(doThisFunction)")
(defun saveVars(/ readlist count item)
Note: This method can be used for a single or multiple selection list_box.
PopUp_List
: popup_list {
key = "mylist";
fixed_width_font = false;
width = 20;
height = 20;
}
// action key
// fixed width font off
// width of popup list
// height of popup list
No Action call required. We will get the selected item when we use the SaveVars
routine. But, sometimes you need to change things in the dialog box if the user makes a
selection, so:
(action_tile "mylist" "(doThisFunction)")
(defun saveVars()
;;;--- Get the selected item from the list
(setq sStr(get_tile "mylist"))
3
(if(= sStr "")(alert "No Item was Selected!"))
)
: radio_column {
label = "Choices";
key = "choices";
: radio_button {
label = "Choice 1";
key = "choice1";
}
: radio_button {
label = "Choice 2";
key = "choice2";
}
: radio_button {
label = "Choice 3";
key = "choice3";
}
: radio_button {
label = "Choice 4";
key = "choice4";
}
No Action call required. We will get the selected item when we use the SaveVars
routine. But, sometimes you need to change things in the dialog box if the user makes a
selection, so:
// If choice1 is made
// If choice2 is made
etc.
(defun saveVars()
;;;--- Get the key of the choice made
;;;
[ returns "choice1" "choice2" "choice3" or "choice4" ]
; 0 = not chosen
; 0 = not chosen
; 0 = not chosen
; 0 = not chosen
1 = chosen
1 = chosen
1 = chosen
1 = chosen
: radio_row {
label = "Choices";
key = "choices";
: radio_button {
label = "Choice 1";
key = "choice1";
}
: radio_button {
label = "Choice 2";
key = "choice2";
}
: radio_button {
label = "Choice 3";
key = "choice3";
}
: radio_button {
label = "Choice 4";
key = "choice4";
}
No Action call required. We will get the selected item when we use the SaveVars
routine. But, sometimes you need to change things in the dialog box if the user makes a
selection, so:
(action_tile "choices" "(doThisFunction)")
made
// If any choice is
// If choice1 is made
// If choice2 is made
etc.
(defun saveVars()
;;;--- Get the key of the choice made
;;;
[ returns "choice1" "choice2" "choice3" or "choice4" ]
(setq choicesVal(get_tile "choices"))
)
OR
(defun saveVars()
;;;--- Get the value of each item
(setq choice1(atoi(get_tile "choice1")))
(setq choice2(atoi(get_tile "choice2")))
(setq choice3(atoi(get_tile "choice3")))
(setq choice4(atoi(get_tile "choice4")))
)
Toggle
: toggle {
key = "tog1";
label = "Name";
}
// Action key
// Label
; 0 = not chosen
; 0 = not chosen
; 0 = not chosen
; 0 = not chosen
1 = chosen
1 = chosen
1 = chosen
1 = chosen
No Action call required. We will get the value of the toggle when we use the SaveVars
routine. But, sometimes you need to change things in the dialog box if the user makes a
selection, so:
(action_tile "tog1" "(doThisFunction)")
(defun saveVars()
;;;--- Get the selected item from the radio column
(setq tog1Val(atoi(get_tile "tog1")))
;0 = unchecked
1 = checked
Ok_Cancel
ok_cancel;
1 Note: I usually define my own okay and cancel buttons using two standard buttons, but
this works fine.
You will need two action calls for this button...both close the dialog box but the accept or
"Okay" key will save the dialog box settings before shutting the dialog box down.
(action_tile "cancel" "(done_dialog 1)")
2
(action_tile "accept" "(saveVars)(done_dialog 2)")
Ahh....finally the SaveVars routine shows up.
Back
LAYOUT CONTROLS:
: column {
label = "My Column";
}
: boxed_column {
label = "My Column";
}
: row {
label = "My Row";
}
: boxed_row {
label = "My Row";
}
: spacer {
width = 10;
height = 15;
}
Column
You can omit the label.
Boxed Column
You can omit the label.
Row
You can omit the label.
Boxed Row
You can omit the label.
: spacer_0;
: spacer_1;
BUTTON
key = The name you assign to the button.
label = The text displayed on the button.
: button {
key = "button1;
label = "Okay";
is_tab_stop = true;
is_cancel = false;
is_default = true;
width = 15;
height = 10;
mnemonic = "B";
}
key = "choice2";
}
: radio_button {
label = "Choice
3";
key = "choice3";
}
: radio_button {
label = "Choice
4";
key = "choice4";
}
}
"choice4";
}
}
EDIT BOX
: edit_box {
key = "myval";
label = "Value:";
edit_width = 10;
value = "";
}
// Action key
// Label for the edit box
// Character width
// Initial value
LIST BOX
: list_box {
label ="Choose Items";
key = "mylist";
height = 15;
width = 25;
multiple_select = true;
fixed_width_font = true;
value = "0";
}
POPUP LIST
: popup_list {
key = "mylist";
label = "Select Item";
fixed_width_font =
false;
width = 15;
value = 0;
}
// Action key
// Label
// Use fixed with font = false
// Width of list box
// Initial selection = 1st item
TEXT
: text {
key = "mytext";
value = "This is text!";
}
// Action key
// Value
Okay. That's it for controls. There are others but, these are the most used controls.
Let's move on.
Back
Column
Column
Column
EXAMPLE : dialog {
label = "EXAMPLE.lsp";
: column {
: boxed_row {
label = "row 1";
: boxed_column {
label = "column2";
}
: boxed_column {
label = "column 3";
}
}
ok_cancel;
}
}
EXAMPLE : dialog {
label = "EXAMPLE.lsp";
: column {
: boxed_column {
label = "column 1";
: boxed_column {
label = "column2";
: text {
key = "t1";
value = "Text1";
}
: text {
key = "t2";
value = "Text2";
}
}
: boxed_column {
label = "column 3";
: text {
key = "t3";
value = "Text3";
}
: text {
key = "t4";
value = "Text4";
}
}
}
ok_cancel;
}
}
Column
Column
Column
EXAMPLE : dialog {
label = "EXAMPLE.lsp";
: column {
: boxed_row {
label = "row 1";
: boxed_column {
label = "column2";
: text {
key = "t1";
value = "Text1";
}
: text {
key = "t2";
value = "Text2";
}
}
: boxed_column {
label = "column 3";
: text {
key = "t3";
value = "Text3";
}
: text {
key = "t4";
value = "Text4";
}
}
}
ok_cancel;
}
}
Row
Column
Column
EXAMPLE : dialog {
label = "EXAMPLE.lsp";
: column {
: boxed_row {
label = "row 1";
: boxed_row {
label = "row 2";
: text {
key = "t1";
value = "Text1";
}
: text {
key = "t2";
value = "Text2";
}
}
: boxed_row {
label = "row 3";
: text {
key = "t3";
value = "Text3";
}
: text {
key = "t4";
value = "Text4";
}
}
}
ok_cancel;
}
}
Row
Row
Row
EXAMPLE : dialog {
label = "EXAMPLE.lsp";
: column {
: boxed_column {
label = "row 1";
: boxed_row {
label = "row 2";
: text {
key = "t1";
value = "Text1";
}
: text {
key = "t2";
value = "Text2";
}
}
: boxed_row {
label = "row 3";
: text {
key = "t3";
value = "Text3";
}
: text {
key = "t4";
value = "Text4";
}
}
}
ok_cancel;
}
}
Column
Row
Row