List Box Synchronisation

Updating a DCL List_Box Based on User Selection from Another List_Box

Here I demonstrate a small example of how to update a secondary DCL list_box tile, based on a user selection from a primary list_box tile. The example I present utilises list_box tiles, however, the concept could very easily be applied to popup_list tiles by merely substituting popup_list for list_box in the Dialog Control Language (DCL) file.

This tutorial assumes the reader knows how to work with DCL using LISP to a basic level.

The example I shall demonstrate incorporates two list_box tiles in a dialog, displaying a selection of car makes & corresponding models for each make of car. The dialog is designed to update the list of available models following a selection of make.

The Code

DCL File

Save this code in an AutoCAD Support Path as: listboxexample.dcl

Select all
// DCL File to be saved as listboxexample.dcl
// Example courtesy of Lee Mac © 2010 (www.lee-mac.com)

lbox : list_box { width = 25; fixed_width = true; alignment = centered; }

listboxexample : dialog { label ="List Box Synchronisation"; spacer;
  : row {
    : lbox { key = "lst1"; label = "Make" ; }
    : lbox { key = "lst2"; label = "Model"; }
  }
  ok_only;
}

LISP File

This may be saved using an arbitrary filename, for loading instructions see How to Run an AutoLISP Program.

When loaded, start the program using ListBoxExample at the command line.

Select all
(defun c:listboxexample ( / *error* UpdateList data dclfile dclhandle )

  ;; This program demonstrates how to update a secondary list_box based
  ;; on user selection from a primary list_box.

  ;; Example courtesy of Lee Mac © 2010 (www.lee-mac.com)

  ;; Accompanying DCL File:

  (setq dclFile "listboxexample.dcl")
  
  ;; Ensure this file resides in an AutoCAD Support Path

  (defun *error* ( msg )

    ;; Error Handler - will unload the dialog
    ;; from memory should the user decide to hit Esc

    (if dclHandle (unload_dialog dclHandle))
    (or (wcmatch (strcase msg) "*BREAK,*CANCEL*,*EXIT*")
        (princ (strcat "\n** Error: " msg " **")))
    (princ)
  )

  (defun UpdateList ( key lst )

    ;; This function updates the list_box associated with the specified key
    ;; using the contents of the supplied lst

    (start_list key)
    (mapcar 'add_list lst)
    (end_list)
  )

  ;; Data used to Populate List_Boxes:
  ;; I've chosen to use this list structure because it suits the data,
  ;; but there are many other possibilities.

  (setq Data
   '(
     ("Audi"    ("TTS Quattro" "TT RS" "S3 Quattro" "S4 Quattro" "S5 Quattro" "RS5 Quattro" "RS6 Quattro"))
     ("BMW"     ("M3" "M5" "M6" "X5" "Z3" "Z4"))
     ("Porsche" ("911" "924" "928" "930" "944" "Boxster" "Cayenne" "Cayman"))
     ("Jaguar"  ("XF" "XJ6" "XJR" "XKR" "X-Type" "S-Type"))      
    )
  )

  ;; Start of Main Routine
  ;; Lots of Error Trapping to make sure the Dialog Loads:

  (cond
    ( (<= (setq dclHandle (load_dialog dclFile)) 0)

      (princ "\n--> DCL File not Found.")
    )
    ( (not (new_dialog "listboxexample" dclHandle))

      (setq dclHandle (unload_dialog dclHandle))
      (princ "\n--> Dialog Definition not Found.")
    )
    ( t
      ;; Dialog Loaded Successfully.

      (or *Make*  (setq *Make*  "0"))
      (or *Model* (setq *Model* "0"))

      ;; Set up some default selections, for the first-time running of the program.
      ;; The variables *Make* & *Model* are intended to be global and hence will
      ;; remember the user's last selections.

      ;; Populate the List_Boxes:

      ;; List_Box 'lst1'
     
      (UpdateList "lst1" (mapcar 'car Data))
      (set_tile "lst1" *Make*)

      ;; List_Box 'lst2'

      (UpdateList "lst2" (cadr (nth (atoi *Make*) Data)))
      (set_tile "lst2" *Model*)

      ;; Action_tile Statements:
      ;; These control what happens when the user interacts with a tile in the dialog.

      (action_tile "lst1"
        (strcat
          "(UpdateList \"lst2\" (setq lst2 (cadr (nth (atoi (setq *Make* $value)) Data))))"
          "(setq *Model*"
          "  (set_tile \"lst2\""
          "    (if (< (atoi *Model*) (length lst2)) *Model* \"0\")"
          "  )"
          ")"
        )
      )

      ;; Here, when the user selects an item from 'lst1', the UpdateList subfunction
      ;; is fired to update the items in list_box 'lst2'.

      ;; list_box 'lst2' is also set to the value of *Model* if the index is
      ;; available for the selected item, else the first item is selected.

      ;; Note that $value is a string containg the index of the item
      ;; that the user has selected.

      (action_tile "lst2" "(setq *Model* $value)")

      ;; Dialog setup, lets start it:

      (start_dialog)
      (setq dclHandle (unload_dialog dclHandle))
    )
  )
  (princ)
)

The Result

List Box Example.gif

textsize

increase · reset · decrease

Designed & Created by Lee Mac © 2010