The AutoLisp Tutorial - DCL

Dialog Control Language - Part 7


   Now it is time to take all of the parts and pieces and put them together.   Let's build a working DCL file that will let us see most of the things we've learned and yet not get to deep into autolisp.

  Lets draw a polygon or circle, on a selected layer with the option to save the settings last used for defaults next time we run the program.  If polygon is chosen, ask for the number of sides.  So....we will need a list_box to hold all of the available layer names.  We will need a radio_column to select a circle or polylgon.   We will need an popup_list to hold the number of sides for the polygon.  We will need a toggle to check the "Save Settings" option.  And last, we will need an Okay and Cancel button.


  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 {

         // Put code for popup_list here [ Number of Sides ]
      }  
      : toggle {

         // Put code for toggle here  [ 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
  (setq dcl_id (load_dialog "SAMPLE7.dcl"))

  ;;;--- Load the dialog definition if it is not already loaded
  (if (not (new_dialog "SAMPLE7" dcl_id) ) (exit))

  ;;;--- If an action event occurs, do this function
  (action_tile "cancel" "(setq ddiag 1)(done_dialog)")
  (action_tile "accept" "(setq ddiag 2)(saveVars)(done_dialog)")

  ;;;--- Display the dialog box
  (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:

 

DCL_PART101.jpg (13229 bytes)

  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
    (setq layerList(append layerList (list(cdr(assoc 2 layr)))))
  )

Short Way: 

(setq layerList(list "0" "DIM" "HIDDEN" "STR" "TX" "WELD"))

We also need a list for the polgon's number of sides:

(setq numSides(list "4" "6" "8" "12" "16"))

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
  (setq dcl_id (load_dialog "SAMPLE7.dcl"))

  ;;;--- Load the dialog definition if it is not already loaded
  (if (not (new_dialog "SAMPLE7" dcl_id) ) (exit))

  (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)

  ;;;--- If an action event occurs, do this function
  (action_tile "cancel" "(setq ddiag 1)(done_dialog)")
  (action_tile "accept" "(setq ddiag 2)(saveVars)(done_dialog)")

  ;;;--- Display the dialog box
  (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)

)


Save, Load, and Run.  You should see this:

DCL_PART102.jpg (14575 bytes)


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))

      ;;;--- 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)
    )
  )
)
   

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.   Everything working okay?  Alrighty then...let's move on.  


  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)

   ;if circle is selected
   (if(= a 1)
      (mode_tile "numsides" 1)   ;disable

      ;else
      (mode_tile "numsides" 0)   ;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.  You should see this:

DCL_PART103.jpg (13796 bytes)

DCL_PART104.jpg (14378 bytes)

The numSides popup_list is disabled when the circle is selected.   Enabled when polygon is selected.  Cool.

Here is the AutoLisp program after the lines above were added:

(defun saveVars()
  (setq radios(get_tile "radios"))

  ;;;--- Get the number of sides selected from the list
  (setq sStr(get_tile "numsides"))
  (if(= sStr "")
    (setq numSides nil)
    (setq numSides(nth (atoi sStr) 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
  (setq dcl_id (load_dialog "SAMPLE7.dcl"))

  ;;;--- Load the dialog definition if it is not already loaded
  (if (not (new_dialog "SAMPLE7" dcl_id) ) (exit))

  (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 event occurs, do this function
  (action_tile "drawcir" "(toggleRadio 1)")
  (action_tile "drawpol" "(toggleRadio 2)")

  (action_tile "cancel" "(setq ddiag 1)(done_dialog)")
  (action_tile "accept" "(setq ddiag 2)(saveVars)(done_dialog)")

  ;;;--- Display the dialog box
  (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)

)


  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 DCL Control Item Action Key Type of Data Stored
radios Radio_Column "radios" String [ Action Key Name]
numSides Popup_List "numsides" Integer [ Number of sides]
saveSet Toggle "saveset" Integer [ 0 or 1 ]
layerName List "layerlist" String [ Name of Layer]

   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)

  That was easy.  Now,  Let's draw the selected entity

(if(= radios "drawcir")
  (progn
    (setq pt(getpoint "\n Center point: "))
    (command "circle" pt pause)
  )
  ;;;--- Else draw a polygon
  (progn
    (setq pt(getpoint "\n Center Point: "))
    (command "polygon" numSides pt "C" pause)
  )
)

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.

(setvar "USERS4" 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
  (setq dcl_id (load_dialog "SAMPLE7.dcl"))

  ;;;--- Load the dialog definition if it is not already loaded
  (if (not (new_dialog "SAMPLE7" dcl_id) ) (exit))

  ;;; Build the list for the dialog box
  (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)


  ;;;--- Add the code here to check for defaults
  (if(/= (getvar "USERS1") "")
    (progn
      (setq radios (getvar "users1"))
      (setq numStr (getvar "users2"))
      (setq saveSet(getvar "users3"))
      (setq layerIndex(getvar "users4"))
      (set_tile "radios" radios)
      (set_tile "numsides" numStr)
      (set_tile "saveset" saveSet)
      (set_tile "layerlist" layerIndex)
    )
  )

  ;;;--- Only disable the numSides popup_list if a circle is being drawn
  (if(= radios "drawcir")
    (mode_tile "numsides" 1)
  )

  ;;;--- If an action event occurs, do this function
  (action_tile "drawcir" "(toggleRadio 1)")
  (action_tile "drawpol" "(toggleRadio 2)")
  (action_tile "cancel" "(setq ddiag 1)(done_dialog)")
  (action_tile "accept" "(setq ddiag 2)(saveVars)(done_dialog)")

  ;;;--- Display the dialog box
  (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)
    (progn

      ;;;--- Save the old layer and reset to new layer
      (setq oldLay(getvar "clayer"))
      (setvar "clayer" layerName)

      ;;;--- See what needs to be drawn
      (if(= radios "drawcir")
        (progn
          (setq pt(getpoint "\n Center point: "))
          (command "circle" pt pause)
        )

        ;;;--- Else draw a polygon
        (progn
          (setq pt(getpoint "\n Center Point: "))
          (command "polygon" numSides pt "C" pause)
        )
      )


      ;;;--- See if we need to save the settings
      (if(= saveSet 1)
        (progn


          ;;;--- Add code here to save the settings as defaults
          (setvar "USERS1" radios)
          (setvar "USERS2" numStr)
          (setvar "USERS3" (itoa saveSet))
          (setvar "USERS4" 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


AutoLisp Tutorial Home