Lisp "Error: bad function" thrown and Help with coding conditions

Lisp "Error: bad function" thrown and Help with coding conditions

The_CADalyst
Contributor Contributor
2,533 Views
10 Replies
Message 1 of 11

Lisp "Error: bad function" thrown and Help with coding conditions

The_CADalyst
Contributor
Contributor

 

I'm trying to create a utility that will ask the users a few questions and then update all instances of a block within appropriately. This also my first attempt at DCL, so it's been a fun process along the way. The issue that I am having is during my initial testing of how the Dialog box functions and behaves, I get an error " ** Error: bad function: "30x42" ** ". One thing I do know is that "30x42" is listed as an available sheet size only for our Arizona off, but regardless of what region and sheet size I choose, I always get the same error. Please see the code below.

 

On additional note since I am here already, would someone help point me in the right direction on how the utility should approach the conditions in the section area of the tbupdater at the bottom. The selections in the dialog box will determine which block to insert, whether for a model or a lot specific, and which insertion point the block should have. So the code should determine the region, whether it is a model or lot specific, then the insertion point based of the sheet size. Some regions only have one sheet size, so those can skip that part.

 

Any and all help will be greatly appreciated, so thank you in advance.

 

Lisp Code:

(defun c:tbu ( / *error* UpdateList data dclfile dclhandle )

	;; Load Visual Lisp Functions
	  (vl-load-com)

	;; Set Undo marker
	  (Setq thisdrawing (vla-get-activedocument (vlax-get-acad-object)))
	  (vla-startundomark thisdrawing)

	;; Load Accompanying DCL File
	  (setq dclFile "tbuu.dcl")
  
	;; Error Handler - will unload the dialog from memory should the user decide to hit Esc
	  (defun *error* ( msg )
		(if dclHandle (unload_dialog dclHandle))
		(or (wcmatch (strcase msg) "*BREAK,*CANCEL*,*EXIT*")
			(princ (strcat "\n** Error: " msg " **"))
			(*return_setvar*)
		)
		(princ)
	  )

	;; Set Variables - will log current values then set them to the appropriate values
	  (defun *new_setvar* ()
		(setq oom (getvar "osmode"))	; store osmode setting
			(setvar "osmode" 0)			; set osmode to 0
		(setq oce (getvar "cmdecho"))	; store cmdecho setting
			(setvar "cmdecho" 0)		; set cmdecho to 0
		(setq ocar (getvar "attreq"))	; store attreq setting
			(setvar "attreq" 0)			; set attreq to 0
		(setq ocfd (getvar "filedia"))	; store filedia setting
			(setvar "filedia" 0)		; set filedia to 0
		(setq occt (getvar "ctab"))		; store current tab name
		  (setvar "tilemode" 0)			; set tilemode to 0
		)

	;; Reset Variables - returns variables to previous logged values	
	  (defun *return_setvar* ()
		(setvar "osmode" oom)	; reset osmode to original setting
		(setvar "cmdecho" oce)	; reset cmdecho to original setting
		(setvar "attreq" ocar)	; reset attreq to original setting
		(setvar "filedia" ocfd)	; reset filedia to original setting
		(setvar "ctab" occt)	; reset to original tab
	  )
	  
  	;; This function updates the list_box associated with the specified key using the contents of the supplied lst
	  (defun UpdateList ( key lst )
		(start_list key)
		(mapcar 'add_list lst)
		(end_list)
	  )

	;; Data used to Populate List_Boxes:
	  (setq Data
	   '(
		 ("Arizona"    		("30x42"))
		 ("California"		("24x36"))
		 ("Colorado"		("22x34"))
		 ("Florida"			("22x34" "24x36" "34x44"))
		 ("Northeast"		("22x34" "24x36" "34x44"))
		 ("Northwest"		("22x34"))
		 ("Texas"			("22x34"))
		 ("Sales Office"	("22x34"))      
		)
	  )

	;; Start of Main Routine with lots of Error Trapping to make sure the Dialog Loads:
	  (cond
		( (<= (setq dclHandle (load_dialog dclFile)) 0)

		  (princ "\ACA> DCL File not Found.")
		)
		( (not (new_dialog "tbuu" dclHandle))

		  (setq dclHandle (unload_dialog dclHandle))
		  (princ "\ACA> Dialog Definition not Found.")
		)
		( t ;; If Dialog Loads Successfully.
		
	;; Log the values of current variables then sets them to appropriate values
		  (*new_setvar*)

	;; Set up some default selections, for the first-time running of the program.
		;; The variables *Region* & *Size* are intended to be global and hence will remember the user's last selections.
		  (or *Model*	(setq *Model* "0"))
		  (or *Lot*		(setq *Lot* "0"))
		  (or *Region*  (setq *Region*  "0"))
		  (or *Size*	(setq *Size* "0"))

	;; Populate the List_Boxes:
		;; List_Box 'tbreg'
		  (UpdateList "tbreg" (mapcar 'car Data))
		  (set_tile "tbreg" *Region*)

		;; List_Box 'tbsize'
		  (UpdateList "tbsize" (cadr (nth (atoi *Region*) Data)))
		  (set_tile "tbsize" *Size*)

	;; Action_tile Statements:
		;; These control the action to evaluate when the user interacts with a tile in the dialog.
	    ;; Note that $value is a string containing the index of the item that the user has selected.
		  (action_tile "mod" "(setq *Model* $value)")
		  (action_tile "lot" "(setq *Lot* $value)")  
		  
		;; Here, when the user selects a region in 'tbreg', the UpdateList subfunction is fired to update the available sheet size in list_box 'tbsize'.
		  (action_tile "tbreg"
			(strcat
			  "(UpdateList \"tbsize\" (setq tbsize (cadr (nth (atoi (setq *Region* $value)) Data))))"
			  "(setq *Size*"
			  "  (set_tile \"tbsize\""
			  "    (if (< (atoi *Size*) (length tbsize)) *Size* \"0\")"
			  "  )"
			  ")"
			)
		  )

		;; list_box 'tbsize' is also set to the value of *Size* if the index is available for the selected item, else the first item is selected.
		  (action_tile "tbsize" "(setq *Size* $value)")
		  
		;; If user clicks OK, this will store the values then run the "tbupdater"
		  (action_tile "accept" 
				(strcat
					"(progn
						(setq tbumod (atof (get_tile \"mod\")))"
					   "(setq tbulot (atof (get_tile \"lot\")))"
					   "(setq tbureg (atof (get_tile \"tbreg\")))"
					   "(setq tbusize (atof (get_tile \"tbsize\")))"
					   "(done_dialog 1)(tbupdater))"
				)
		  )
		  
		;; If user clicks Cancel, this will close the dialog box and then return the variables back to previous values  
		  (action_tile "cancel" "(done_dialog 0)")
		  
		;; Dialog setup complete, now lets start it:
		  (start_dialog)
		  (setq dclHandle (unload_dialog dclHandle))
		)
	  )
	;; End UNDO marker
		(vla-endundomark thisdrawing)
  (princ)
); end of tbu


;|
(defun tbupdater ()

;; Remove All inserted TB Props followed by purging all blocks
	(DELTB7)

;| Planning	
	If Region = Arizona
		and Model is selected
			Size is always 30x42
				Insert TB Props at x=0 y=0 z=0
		or Lot is selected
			Size is always 30x42
				Insert TB Props Lots at x=0 y=0 z=0
		
	If Region = California 
		and Model is selected
			Size is always 24x36
				Insert TB Props at x=0 y=0 z=0
		or Lot is selected
			Size is always 24x36
				Insert TB Props Lots at x=0 y=0 z=0

	If Region = Colorado
		and Model is selected
			Size is always 22x34
				Insert TB Props at x=0 y=0 z=0
		or Lot is selected
			Size is always 22x34
				Insert TB Props Lots at x=0 y=0 z=0
			
	If Region = Florida
		and Model is selected
			and size is
				22x34
					Insert TB Props at x=2'-7 1/16" y=9/16" z=0
				24x36
					Insert TB Props at x=2'-9 1/16" y=9/16" z=0
				34x44
					Insert TB Props at x=3'-5 1/16" y=9/16" z=0
		or Lot is selected
			and size is
				22x34
					Insert TB Props Lots at x=2'-7 1/16" y=9/16" z=0
				24x36
					Insert TB Props Lots at x=2'-9 1/16" y=9/16" z=0
				34x44
					Insert TB Props Lots at x=3'-5 1/16" y=9/16" z=0

	If Region = Northeast
		and Model is selected
			and size is
				22x34
					Insert TB Props at x=2'-7 1/16" y=9/16" z=0
				30x42
					Insert TB Props at x=3'-3 1/16" y=9/16" z=0
				34x44
					Insert TB Props at x=3'-5 1/16" y=9/16" z=0
		or Lot is selected
			and size is
				22x34
					Insert TB Props Lots at x=2'-7 1/16" y=9/16" z=0
				24x36
					Insert TB Props Lots at x=2'-9 1/16" y=9/16" z=0
				34x44
					Insert TB Props Lots at x=3'-5 1/16" y=9/16" z=0
			
	If Region = Northwest
		and Model is selected
			Size is always 22x34
				Insert TB Props at x=0 y=0 z=0
		or Lot is selected
			Size is always 22x34
				Insert TB Props Lots at x=0 y=0 z=0
			
	If Region = Sales Office (Northeast TB Props)
		Size is always 22x34
			Insert TB Props at x=2'-7 1/16" y=9/16" z=0

	If Region = Texas
		and Model is selected
			Size is always 22x34
				Insert TB Props at x=0 y=0 z=0
		or Lot is selected
			Size is always 22x34
				Insert TB Props Lots at x=0 y=0 z=0
|;
	
	(princ)
	(princ "\nTCS> The Titleblock Properties within this drawing have been updated.")
); end of tbupdater

 

 

 

DCL Code:

// To be saved within a support path and named "tbuu.dcl"

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

tbuu : dialog { label ="Update Titleblock Properties Utility"; spacer;
				  : radio_row {label = "Model or Lot :";
						: radio_button {key = "mod"; label = "&Model"; value = 1; }
						: radio_button {key = "lot"; label = "&Lot"; value = 0; }
							}				  
				  : row {
					: lbox { key = "tbreg"; label = "&Region or Department :" ; }
					: lbox { key = "tbsize"; label = "S&heet Size :"; }
				  }
				  ok_cancel ;
			}

 

0 Likes
2,534 Views
10 Replies
Replies (10)
Message 2 of 11

john.uhden
Mentor
Mentor

I didn't follow it that closely, but it seems that it's a problem of how you treat (cadr) of any 'data' item because (cadr) of any 'data' item will return a list of sizes.  So if treated literally ("30x42") calls for a function named "30x42" which most probably does not exist.  In fact you can't create any function or symbol with quotes at each end of its name, so it flatly does not exist.

John F. Uhden

0 Likes
Message 3 of 11

paullimapa
Mentor
Mentor

First of all, I did not receive any errors executing your program.  Overall, it looks well thought out and you are well on your way to a very successful first try using DCL.  I would suggest you go a step further by using Lisp to write the DCL file on the fly.  This way you can designate where the DCL should be written and then loaded.  After the Lisp routine completes, then cleanly complete the routine by deleting the DCL file.

 

There is a section under action_tile "accept" that I would change. 

You don't need to use progn and instead of using atof I would use atoi to convert the text string to an integer for extracting the list position for both your tbureg & tbusize.  

 

(action_tile "accept"
"(setq tbumod (atoi(get_tile \"mod\")))
(setq tbulot (atoi(get_tile \"lot\")))
(setq tbureg (atoi(get_tile \"tbreg\")))
(setq tbusize (atoi(get_tile \"tbsize\")))
(done_dialog 1)(tbupdater))"
)

 

Your region would be:

(setq reg (car (nth tbureg data)))

 

Your papersize would be:

(setq siz (nth tbusize(cadr(nth tbureg data))))

 

Then you can use these values to complete the routine.

 

Area Object Link | Attribute Modifier | Dwg Setup | Feet-Inch Calculator
Layer Apps | List on Steroids | VP Zoom Scales | Exchange App Store


Paul Li
IT Specialist
@The Office
Apps & Publications | Video Demos
Message 4 of 11

scot-65
Advisor
Advisor
;; If user clicks OK, this will store the values then run the "tbupdater"
(action_tile "accept" 
 (strcat
  "(progn
   (setq tbumod (atof (get_tile \"mod\")))"
  "(setq tbulot (atof (get_tile \"lot\")))"
  "(setq tbureg (atof (get_tile \"tbreg\")))"
  "(setq tbusize (atof (get_tile \"tbsize\")))"
  "(done_dialog 1)(tbupdater))"
 )
)

Lets rewrite this a little...

 

   (action_tile "accept" "(TBU_GET)(done_dialog 1)")

   (action_tile "cancel" "(done_dialog 0)")

 

Note that there are a total of 4 quotes (") in this above line.

Any additional without escaping (\") will throw an error.

Any and all coding must be located inside the last two quotes.

 

Add a key to the radio row [radio cluster container]

: radio_row {key="ModLot"; label = "Model or Lot :";

 

(defun TBU_GET ()

 (setq USER_TBU (list

  (get_tile "ModLot")

  (get_tile "tbreg")

  (get_tile "tbsize")

 ));setq

);end TBU_GET

 

tbreg and tbsize are index positions for the list boxes.

You will need to convert to integer at the point you will reference this list.

For example, (atoi (nth 1 USER_TBU))

 

Other (random) hints...

Introduce a Gremlin [session only] - USER_TBU so the dialog is initialized properly.

done_dialog has the option of returning an integer to start_dialog.

We will capture this integer using 'sd', then enter into the main execution part of the program.

 

;<-- new_dialog -->

;*** Initialize ***

(or USER_TBU (setq USER_TBU (list "mod" "0" "0")))

;*** Set Tile ***

(set_tile "ModLot" (nth 0 USER_TBU))

;<-- populate list box tbreg here -->

(set_tile "tbreg" (nth 1 USER_TBU))

;<-- populate list box tbsize here -->

(set_tile "tbsize" (nth 2 USER_TBU))

;*** Mode Tile ***

;...as required

;*** Action Tile ***

;...as required

(setq sd (start_dialog))

 

(if (and sd (= sd 1))

 ;<-- main execution -->

);if

 

Now, the next time you run the program, the values will be set to the same values at the time the dialog was closed successfully.

 

???


Scot-65
A gift of extraordinary Common Sense does not require an Acronym Suffix to be added to my given name.

Message 5 of 11

scot-65
Advisor
Advisor

Perhaps one does not want any tiles initialized?
When the dialog is opened, and nothing is initialized,
get_tile will return nil and may cause problems later.

There are 2 ways to go about this. The first method
generally is for simple dialogs while the second method
is for more involved dialogs (especially when checking
input from edit boxes).

First method (no initialization):

  Suppress the accept button.

;*** Set Tile ***
...
;*** Mode Tile ***
(mode_tile "accept" 1)
;*** Action Tile ***
(action_tile "Rad01" "(VAL_Check)")
(action_tile "Rad02" "(VAL_Check)")
(action_tile "Lis01" "(VAL_Check)")
(action_tile "Lis02" "(VAL_Check)")
...

  where

(defun VAL_Check ()
 (if (and (get_tile "Rad00")(get_tile "Lis01")(get_tile "Lis02"))
  (mode_tile "accept" 0)
 );if
);defun

  will turn on the OK button when all is satisfied.

Note that radio buttons are nil to begin with (not "0"). When one
radio button is activated, all the other radio buttons will be set
to "0". The container for the radio buttons will return the key name
of the currently activated radio button. Use the container's key to
set and get the currently selected radio button tile.

Also note that "accept" and "cancel" are the only other action_tile
lines that are needed for the dialog. No need to setq "mod", "log", etc.
in the action tile area since one is grabbing the values anyways when
accept is selected [using TBU_GET].


Second method (no initialization):
  Rewrite the accept line. Alert returns nil and dialog will not close.

;*** Action Tile ***
(action_tile "accept" "(if (TBU_GET) (done_dialog 1))")

  where

(defun TBU_GET ()
 (cond
  ((not (get_tile "Rad00")) (alert "Specify one or other."))
  ((not (get_tile "Lis01")) (alert "Specify first option."))
  ((not (get_tile "Lis02")) (mode_tile "Lis02" 2)(alert "Specify second option."))
  (setq USER_TBU (list
   (get_tile "Rad00")
   (get_tile "Lis01")
   (get_tile "Lis02")
  ));setq
 );cond
);defun

Use this second method where extensive dialogs or where edit box error checking.

Optional is to (mode_tile "tile" 2) before the alert statement so focus will be set to

the culprit tile when the user closes the alert box (that is in front of the still-open

dialog box).

 

Hope this helps.

 


Scot-65
A gift of extraordinary Common Sense does not require an Acronym Suffix to be added to my given name.

Message 6 of 11

The_CADalyst
Contributor
Contributor

I had a beta version that done that, but the issue that I was having that throughout my testing process, I had accrued about 100 dcl files in my temp folder. This is because the source code that I found created a new version each time the command was run. If I knew how to write one so that it would create a single temp dcl file in the location that the lisp was located, check to see if this exists when the command is run or create a new one if not present, then I would implement that option. My knowledge of Diesel is still too limited to approach that correctly.

 

The issue I am having with running the insert command using the users selection is all the IF, AND, OR, and COND lingo. I don't know to approach it. It has to insert this block across all layout tabs, so I will need to have a part that uses:

 

(foreach x (layoutlist)
  (setvar 'ctab x)
  (command "-Insert" "C:/_Vault/_Region Standards/Northwest/_Titleblocks/Titleblock_Properties.dwg" "0,0,0" "1" "1" "0" )
 );end of foreach

 

 

For the Insertion command, here is what I believe the logic to be:

 

The region is used as part of the pathname of where the appropriate block is located. Every region has their own standards folder. So the insert command would look like:

 

(command "-Insert" "C:/_Vault/_Region Standards/" tbreg  "/_Titleblocks/Titleblock_Properties.dwg" "0,0,0" "1" "1" "0" )

Connecting these (3) path segments together into one is boggling me.

 

 

There is also (2) blocks located here. One is for models (Titleblock_Properties.dwg) and the other is for lot specifics (Titleblock_Properties_Lot.dwg, so depending on which they choose determines what the last segment of the path location is.

 

Model - "/_Titleblocks/Titleblock_Properties.dwg"

Lot - "/_Titleblocks/Titleblock_Properties_Lot.dwg"

 

So the insertion command would be something like this?:

(command "-Insert" "C:/_Vault/_Region Standards/" tbreg  ModLot "0,0,0" "1" "1" "0" )

 

 

Then, to add another layer to the onion, there is the Sheet size that will determine the insertion location of the block. All blocks are created to insert at 0,0,0 EXCEPT our Notheast and Florida offices, who botched the creation of their block, so their insertion points is 2'-7 1/16", 9/16", 0....smh. So now I have to muddy up the code to factor for this. What I know is: Arizona, California, Colorado, Northwest, and Texas can insert at 0,0,0 and Northeast and Florida have to insert at 2'-7 1/16", 9/16", 0. So tbsize needs to evaluate these conditions and then factor the selected sheet size.

 

So now the insertion command would be something like this?:

(command "-Insert" "C:/_Vault/_Region Standards/" tbreg  ModLot tbsize"1" "1" "0" )

 

 

 If Region = Arizona
  and Model is selected
   Size is always 30x42
    Insert TB Props at x=0 y=0 z=0
  or Lot is selected
   Size is always 30x42
    Insert TB Props Lots at x=0 y=0 z=0
  
 If Region = California
  and Model is selected
   Size is always 24x36
    Insert TB Props at x=0 y=0 z=0
  or Lot is selected
   Size is always 24x36
    Insert TB Props Lots at x=0 y=0 z=0

 

 If Region = Colorado
  and Model is selected
   Size is always 22x34
    Insert TB Props at x=0 y=0 z=0
  or Lot is selected
   Size is always 22x34
    Insert TB Props Lots at x=0 y=0 z=0
   
 If Region = Florida
  and Model is selected
   and size is
    22x34
     Insert TB Props at x=2'-7 1/16" y=9/16" z=0
    24x36
     Insert TB Props at x=2'-9 1/16" y=9/16" z=0
    34x44
     Insert TB Props at x=3'-5 1/16" y=9/16" z=0
  or Lot is selected
   and size is
    22x34
     Insert TB Props Lots at x=2'-7 1/16" y=9/16" z=0
    24x36
     Insert TB Props Lots at x=2'-9 1/16" y=9/16" z=0
    34x44
     Insert TB Props Lots at x=3'-5 1/16" y=9/16" z=0

 

 If Region = Northeast
  and Model is selected
   and size is
    22x34
     Insert TB Props at x=2'-7 1/16" y=9/16" z=0
    30x42
     Insert TB Props at x=3'-3 1/16" y=9/16" z=0
    34x44
     Insert TB Props at x=3'-5 1/16" y=9/16" z=0
  or Lot is selected
   and size is
    22x34
     Insert TB Props Lots at x=2'-7 1/16" y=9/16" z=0
    24x36
     Insert TB Props Lots at x=2'-9 1/16" y=9/16" z=0
    34x44
     Insert TB Props Lots at x=3'-5 1/16" y=9/16" z=0
   
 If Region = Northwest
  and Model is selected
   Size is always 22x34
    Insert TB Props at x=0 y=0 z=0
  or Lot is selected
   Size is always 22x34
    Insert TB Props Lots at x=0 y=0 z=0
   
 If Region = Sales Office (Northeast TB Props)
  Size is always 22x34
   Insert TB Props at x=2'-7 1/16" y=9/16" z=0

 If Region = Texas
  and Model is selected
   Size is always 22x34
    Insert TB Props at x=0 y=0 z=0
  or Lot is selected
   Size is always 22x34
    Insert TB Props Lots at x=0 y=0 z=0

0 Likes
Message 7 of 11

The_CADalyst
Contributor
Contributor

I was able to implement your suggested code, and got it working I believe. I still have (2) issues with it though. First, it is not remembering whether I had previously selected Model or Lot. So when I restart the utility, it defaults to Model. I had seen some methods where these values was stored as registry values and or environment variables. Those will allow CAD to call them up even after the program was restarted, but I didn't want to muddy up the waters with your suggested code. Second, I can't seem to get the (tbuupdater) command to run after the user clicks OK. I have added it to the accept button and at the end of TBU_GET, but both throw the same error.

 

 

PS. If you have any input on how to approach the conditions that I posted above, it would be greatly appreciated.

 

 

Latest Lisp Code:

(defun c:tbu ( / *error* UpdateList data dclfile dclhandle )

	;; Load Visual Lisp Functions
	  (vl-load-com)

	;; Set Undo marker
	  (Setq thisdrawing (vla-get-activedocument (vlax-get-acad-object)))
	  (vla-startundomark thisdrawing)

	;; Load Accompanying DCL File
	  (setq dclFile "tbuu.dcl")
  
	;; Error Handler - will unload the dialog from memory should the user decide to hit Esc
	  (defun *error* ( msg )
		(if dclHandle (unload_dialog dclHandle))
		(or (wcmatch (strcase msg) "*BREAK,*CANCEL*,*EXIT*")
			(princ (strcat "\n** Error: " msg " **"))
			(*return_setvar*)
		)
		(princ)
	  )

	;; Set Variables - will log current values then set them to the appropriate values
	  (defun *new_setvar* ()
		(setq oom (getvar "osmode"))	; store osmode setting
			(setvar "osmode" 0)			; set osmode to 0
		(setq oce (getvar "cmdecho"))	; store cmdecho setting
			(setvar "cmdecho" 0)		; set cmdecho to 0
		(setq ocar (getvar "attreq"))	; store attreq setting
			(setvar "attreq" 0)			; set attreq to 0
		(setq ocfd (getvar "filedia"))	; store filedia setting
			(setvar "filedia" 0)		; set filedia to 0
		(setq occt (getvar "ctab"))		; store current tab name
		  (setvar "tilemode" 0)			; set tilemode to 0
		)

	;; Reset Variables - returns variables to previous logged values	
	  (defun *return_setvar* ()
		(setvar "osmode" oom)	; reset osmode to original setting
		(setvar "cmdecho" oce)	; reset cmdecho to original setting
		(setvar "attreq" ocar)	; reset attreq to original setting
		(setvar "filedia" ocfd)	; reset filedia to original setting
		(setvar "ctab" occt)	; reset to original tab
	  )
	  
  	;; This function updates the list_box associated with the specified key using the contents of the supplied lst
	  (defun UpdateList ( key lst )
		(start_list key)
		(mapcar 'add_list lst)
		(end_list)
	  )

	  
	;; Collects the users selections and then start the TBUPDATER
	  (defun TBU_GET ()
		(setq USER_TBU (list
			(get_tile "ModLot")
			(get_tile "tbreg")
			(get_tile "tbsize")
		));setq
	  );end TBU_GET

	  
	;| DISABLED - Code required to disable the OK button until all the sections are made
	  
	  ;; Verifies that all conditions are met then enables the OK button
	  (defun VAL_Check ()
		(if (and (get_tile "ModLot")(get_tile "tbreg")(get_tile "tbsize"))
		  (mode_tile "accept" 0)
		);if
	  );defun
	  
	  ;; These set the prerequisites to enable the OK button - Currently Disabled
		  (action_tile "ModLot" "(VAL_Check)")
		  (action_tile "tbreg" "(VAL_Check)")
		  (action_tile "tbsize" "(VAL_Check)")
	|; 
	  
	  
	  
	;; Data used to Populate List_Boxes:
	  (setq Data
	   '(
		 ("Arizona"    		("30x42"))
		 ("California"		("24x36"))
		 ("Colorado"		("22x34"))
		 ("Florida"			("22x34" "24x36" "34x44"))
		 ("Northeast"		("22x34" "24x36" "34x44"))
		 ("Northwest"		("22x34"))
		 ("Texas"			("22x34"))
		 ("Sales Office"	("22x34"))      
		)
	  )

	;; Start of Main Routine with lots of Error Trapping to make sure the Dialog Loads:
	  (cond
		( (<= (setq dclHandle (load_dialog dclFile)) 0)

		  (princ "\ACA> DCL File not Found.")
		)
		( (not (new_dialog "tbuu" dclHandle))

		  (setq dclHandle (unload_dialog dclHandle))
		  (princ "\ACA> Dialog Definition not Found.")
		)
		( t ;; If Dialog Loads Successfully.
		
	;; Log the values of current variables then sets them to appropriate values
		  (*new_setvar*)

	;; Set up some default selections, for the first-time running of the program.
		;; The variables *Region* & *Size* are intended to be global and hence will remember the user's last selections.
		  (or *Model*	(setq *Model* "0"))
		  (or *Lot*		(setq *Lot* "0"))
		  (or *Region*  (setq *Region*  "0"))
		  (or *Size*	(setq *Size* "0"))

	;; Populate the List_Boxes:
		;; List_Box 'tbreg'
		  (UpdateList "tbreg" (mapcar 'car Data))
		  (set_tile "tbreg" *Region*)

		;; List_Box 'tbsize'
		  (UpdateList "tbsize" (cadr (nth (atoi *Region*) Data)))
		  (set_tile "tbsize" *Size*)

	;; Action_tile Statements:
		;; These control the action to evaluate when the user interacts with a tile in the dialog.
	    ;; Note that $value is a string containing the index of the item that the user has selected.
		  (action_tile "mod" "(setq *Model* $value)")
		  (action_tile "lot" "(setq *Lot* $value)")  
		  
		;; Here, when the user selects a region in 'tbreg', the UpdateList subfunction is fired to update the available sheet size in list_box 'tbsize'.
		  (action_tile "tbreg"
			(strcat
			  "(UpdateList \"tbsize\" (setq tbsize (cadr (nth (atoi (setq *Region* $value)) Data))))"
			  "(setq *Size*"
			  "  (set_tile \"tbsize\""
			  "    (if (< (atoi *Size*) (length tbsize)) *Size* \"0\")"
			  "  )"
			  ")"
			)
		  )

		;; list_box 'tbsize' is also set to the value of *Size* if the index is available for the selected item, else the first item is selected.
		  (action_tile "tbsize" "(setq *Size* $value)")
		  
		;; If user clicks OK, this will store the values then run the "TBUPDATER"
		  (action_tile "accept" "(TBU_GET)(done_dialog 1)")
		  
		;; If user clicks Cancel, this will close the dialog box and then return the variables back to previous values  
		  (action_tile "cancel" "(done_dialog 0)")
		  
		;; Dialog setup complete, now lets start it:
		  (start_dialog)
		  (setq dclHandle (unload_dialog dclHandle))
		)
	  )
	;; End UNDO marker
		(vla-endundomark thisdrawing)
  (princ)
); end of tbu



(defun TBUPDATER ()

;; Remove All inserted TB Props followed by purging all blocks
	(DELTB7);in house command that deletes all TB Props from all tabs
	
	(princ)
	(princ "\nTCS> The Titleblock Properties within this drawing have been updated.")
); end of TBUPDATER

 

 

Latest DCL Code:

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

tbuu : dialog { label ="Titleblock Properties Update Utility"; spacer;
				  : radio_row {key="ModLot"; label = "Model or Lot :";
						: radio_button {key = "mod"; label = "&Model"; value = 1; }
						: radio_button {key = "lot"; label = "&Lot"; value = 0; }
							}				  
				  : row {
					: lbox { key = "tbreg"; label = "&Region or Department :" ; }
					: lbox { key = "tbsize"; label = "S&heet Size :"; }
				  }
				  ok_cancel ;
			}

 

 

0 Likes
Message 8 of 11

scot-65
Advisor
Advisor
;; Set up some default selections, for the first-time running of the program.
;; The variables *Region* & *Size* are intended to be global and hence will remember the user's last selections.
(or *Model* (setq *Model* "0"))
(or *Lot* (setq *Lot* "0"))
(or *Region* (setq *Region* "0"))
(or *Size* (setq *Size* "0"))

;;All of the above is not needed for the dialog to run. Populate these variables
after the dialog is closed.

;; Populate the List_Boxes:
;; List_Box 'tbreg'
(UpdateList "tbreg" (mapcar 'car Data))
xxx (set_tile "tbreg" *Region*)

;; List_Box 'tbsize'
(UpdateList "tbsize" (cadr (nth (atoi *Region*) Data)))
xxx (set_tile "tbsize" *Size*)

I'm guessing you are using the mode_tile method?
Yes = USER_TBU is not initialized on the first run to set the tiles.
When the accept key is selected, USER_TBU will be written so the next
time dialog is opened, the tiles will show the same state as the
previous closing.

(if USER_TBU
(progn
(set_tile "ModLot" (nth 0 USER_TBU))
(set_tile "tbreg" (nth 1 USER_TBU))
(set_tile "tbsize" (nth 2 USER_TBU))
);progn
(mode_tile "accept" 1)
);if
make sure this section is placed AFTER 'add_list (and before action_tile).

action_tile "mod" "lot" "tbreg" and "tbsize" is not needed.
USER_TBU will store these values during accept. Think of it as
taking a snapshot of the dialog when "accept" is pressed.
You can set the appropriate variables after the dialog closes (using NTH).

Since this program is designed for a file-specific environment, I would
use VLAX-LDATA-PUT and VLAX-LDATA-GET to store and retrieve
the values from the file's dictionary. Not the registry. Overall I do not
think this program requires ANY storage method. Just use a session
only Gremlin [USER_TBU].

Because you use so many tabs, it is hard for me to read what you have.
The code pane is too narrow here on my end.

???

Scot-65
A gift of extraordinary Common Sense does not require an Acronym Suffix to be added to my given name.

0 Likes
Message 9 of 11

The_CADalyst
Contributor
Contributor

Sorry about that. Here is a slimmed version of the current code. Thanks in advance for all your help.

 

(defun c:tbu ( / *error* UpdateList data dclfile dclhandle )

;; Load Visual Lisp Functions
(vl-load-com)

;; Set Undo marker
(Setq thisdrawing (vla-get-activedocument (vlax-get-acad-object)))
(vla-startundomark thisdrawing)

;; Load Accompanying DCL File
(setq dclFile "tbuu.dcl")

;; Error Handler - will unload the dialog from 
;; memory should the user decide to hit Esc
(defun *error* ( msg )
(if dclHandle (unload_dialog dclHandle))
(or (wcmatch (strcase msg) "*BREAK,*CANCEL*,*EXIT*")
(princ (strcat "\n** Error: " msg " **"))
(*return_setvar*)
)
(princ)
)

;; Set Variables - will log current values then 
;; set them to the appropriate values
(defun *new_setvar* ()
(setq oom (getvar "osmode"))	; store osmode setting
(setvar "osmode" 0)			; set osmode to 0
(setq oce (getvar "cmdecho"))	; store cmdecho setting
(setvar "cmdecho" 0)		; set cmdecho to 0
(setq ocar (getvar "attreq"))	; store attreq setting
(setvar "attreq" 0)			; set attreq to 0
(setq ocfd (getvar "filedia"))	; store filedia setting
(setvar "filedia" 0)		; set filedia to 0
(setq occt (getvar "ctab"))		; store current tab name
(setvar "tilemode" 0)			; set tilemode to 0
)

;; Reset Variables - returns variables to previous logged values	
(defun *return_setvar* ()
(setvar "osmode" oom)	; reset osmode to original setting
(setvar "cmdecho" oce)	; reset cmdecho to original setting
(setvar "attreq" ocar)	; reset attreq to original setting
(setvar "filedia" ocfd)	; reset filedia to original setting
(setvar "ctab" occt)	; reset to original tab
)

;; This function updates the list_box associated with the 
;; specified key using the contents of the supplied lst
(defun UpdateList ( key lst )
(start_list key)
(mapcar 'add_list lst)
(end_list)
)


;; Collects the users selections and then start the TBUPDATER
(defun TBU_GET ()
(setq USER_TBU (list
(get_tile "ModLot")
(get_tile "tbreg")
(get_tile "tbsize")
));setq
);end TBU_GET


;| DISABLED - 
;; Code required to disable the OK button until all the sections are made

;; Verifies that all conditions are met then enables the OK button
(defun VAL_Check ()
(if (and (get_tile "ModLot")(get_tile "tbreg")(get_tile "tbsize"))
(mode_tile "accept" 0)
);if
);defun

;; These set the prerequisites to enable the OK button - Currently Disabled
(action_tile "ModLot" "(VAL_Check)")
(action_tile "tbreg" "(VAL_Check)")
(action_tile "tbsize" "(VAL_Check)")
|; 

;; Data used to Populate List_Boxes:
(setq Data
'(
("Arizona"    		("30x42"))
("California"		("24x36"))
("Colorado"		("22x34"))
("Florida"			("22x34" "24x36" "34x44"))
("Northeast"		("22x34" "24x36" "34x44"))
("Northwest"		("22x34"))
("Texas"			("22x34"))
("Sales Office"	("22x34"))      
)
)

;; Start of Main Routine with lots of Error Trapping 
;; to make sure the Dialog Loads:
(cond
( (<= (setq dclHandle (load_dialog dclFile)) 0)

(princ "\ACA> DCL File not Found.")
)
( (not (new_dialog "tbuu" dclHandle))

(setq dclHandle (unload_dialog dclHandle))
(princ "\ACA> Dialog Definition not Found.")
)
( t ;; If Dialog Loads Successfully.

;; Log the values of current variables then sets them to appropriate values
(*new_setvar*)

;; Set up some default selections, for the first-time running of the program.
;; The variables *Region* & *Size* are intended to be global 
;; and hence will remember the user's last selections.
(or *Model*	(setq *Model* "0"))
(or *Lot*		(setq *Lot* "0"))
(or *Region*  (setq *Region*  "0"))
(or *Size*	(setq *Size* "0"))

;; Populate the List_Boxes:
;; List_Box 'tbreg'
(UpdateList "tbreg" (mapcar 'car Data))
(set_tile "tbreg" *Region*)

;; List_Box 'tbsize'
(UpdateList "tbsize" (cadr (nth (atoi *Region*) Data)))
(set_tile "tbsize" *Size*)

;; Action_tile Statements:
;; These control the action to evaluate when the user 
;; interacts with a tile in the dialog.
;; Note that $value is a string containing the index of 
;; the item that the user has selected.
(action_tile "mod" "(setq *Model* $value)")
(action_tile "lot" "(setq *Lot* $value)")  

;; Here, when the user selects a region in 'tbreg', 
;; the UpdateList subfunction is fired to update the 
;; available sheet size in list_box 'tbsize'.
(action_tile "tbreg"
(strcat
"(UpdateList \"tbsize\" (setq tbsize (cadr (nth (atoi (setq *Region* $value)) Data))))"
"(setq *Size*"
"  (set_tile \"tbsize\""
"    (if (< (atoi *Size*) (length tbsize)) *Size* \"0\")"
"  )"
")"
)
)

;; list_box 'tbsize' is also set to the value of *Size* 
;; if the index is available for the selected item, 
;; else the first item is selected.
(action_tile "tbsize" "(setq *Size* $value)")

;; If user clicks OK, this will store the values then run the "TBUPDATER"
(action_tile "accept" "(TBU_GET)(done_dialog 1)")

;; If user clicks Cancel, this will close the dialog box 
;; and then return the variables back to previous values  
(action_tile "cancel" "(done_dialog 0)")

;; Dialog setup complete, now lets start it:
(start_dialog)
(setq dclHandle (unload_dialog dclHandle))
)
)
;; End UNDO marker
(vla-endundomark thisdrawing)
(princ)
); end of tbu



(defun TBUPDATER ()

;; Remove All inserted TB Props followed by purging all blocks
(DELTB7)

(princ)
(princ "\nTCS> The Titleblock Properties within this drawing have been updated.")
); end of TBUPDATER
0 Likes
Message 10 of 11

scot-65
Advisor
Advisor

More random hints:

 

In your DCL file, remove VALUE for both radio buttons.

 

 


(action_tile "tbreg" "(UpdateList \"tbsize\" (cadr (nth (atoi $value)) Data))")

 

The above line does not set_tile for the sheet size list box. It is possible to set it to "0" at this time or

(mode_tile "accept" 1) to disable the OK button.

 

(action_tile "tbsize" "(setq *Size* $value)") ;<-- not needed. USER_TBU will catch this.

 

 (setq sd (start_dialog))

 

...unload dialog

 

;*** Main Program ***

(if (and sd (= sd 1))

 (progn

  (if (= (nth 0 USER_TBU) "model")

   (setq *model* 1 *lot* 0)

   (setq *model* 0 *lot* 1)

  );if

  (setq *region* (nth 1 USER_TBU)) ;<-- convert list box position to list item here.

  (setq *size* (nth 2 USER_TBU))

  (TBUPDATER)

 );progn

);if

 

I have a template when creating DCL type programs. Take a look and see if it makes sense.

 

???

 


Scot-65
A gift of extraordinary Common Sense does not require an Acronym Suffix to be added to my given name.

0 Likes
Message 11 of 11

The_CADalyst
Contributor
Contributor

@scot-65 wrote:

 

I have a template when creating DCL type programs. Take a look and see if it makes sense.

 


This is a nice template. Thank you for sharing that.

0 Likes