Jump to content

Need help with EED/Xdata


BCL

Recommended Posts

Hello all, first time poster. I am an amateur programmer and novice autoCAD user. I am trying to create a project in visualLISP and am having trouble with EED/Xdata. I want to be able to select an entity (in my case 99% of the time it will be a straight line) and add custom data to it. It will always have the same numbers of data entries, 9 (do I need to be looking into Xrecord?), but for each entity the actual data will be different.

 

I have found some code that accomplishes something similar to what I'm trying to achieve so I have been using it as a template. I have heavily modified it but continually get an DXF error - If anyone could show me how to accomplish this using edit_box's as opposed to popup_lists (this is what my "template" uses). I have also commented out portions of the code that I have questions about, they are the ones too the right (the authors are directly underneath.

 

as I have stated I am not an autoCAD power user but do have some OOP experience - any sample code, literature or tutorials would be greatly appreciated.

 

 

thank you,

 

Brian Levens

 

 

This is my current DCL file - it will eventually have 9 fields but first things first.

 

2017-07-25 14_57_24-Autodesk AutoCAD 2018 - UNREGISTERED VERSION - [FourLines.dwg].png

 

This is the template that I was trying to manipulate to do what I wanted

(not my code)

 

(defun c:exbolt ( / )
;define function

(setvar "cmdecho" 0)                               
;switch off command echo

(prompt "\nSelect the Line to add data to : ")
;prompt the user

(setq e (entget (car (entsel)) '("AFRALISP")))
;get the associative code list

(setq e1 (assoc -3 e))                              ;what is the assoc doing?
;get the xdata

(if (not e1)
;if there is no exdata

(progn
;do the following

(if (not (tblsearch "APPID" "AFRALISP"))
;check if the application has been registered
	
	(regapp "AFRALISP")
	;if not, register it

);if

	(setq e1 '(( -3 ("AFRALISP"                ;I'm not to sure exactly this code works
		  (1000 . "3")                     ;I know that 1000 is the DXF reference and the -3 is in 
		  (1000 . "3")                     ;reference to the xdata
  		  (1000 . "3")
	))))
	;create a default xdata list
	
	(setq e (append e e1))
	;append to to the main list

	(entmod e)
	;modify the entity
	
);progn

);if

(setq e2 (assoc -3 e))
;get the code -3 list

(setq e3 (car (cdr e2)))
;get the exdata list

(setq SIZ (cdr (nth 1 e3)))
;get the bolt size index number

(setq SIZ1 (cdr (nth 2 e3)))
;get the bolt length index number

(setq gr (cdr (nth 3 e3)))
;get the bolt grade

(setq userclick T)
;set flag

(setq NAMES '("M6" "M8" "M10" "M12" "M16" "M20" "M24" "M30" "M36"
	      ))
;create list of bolt sizes


(setq LEN '("10" "15" "20" "25" "30" "35" "40" "45" "50" "55" "60"))
;create list of bolt lengths

(setq dcl_id (load_dialog "exbolt.dcl"))
;load dialogue

(if (not (new_dialog "exbolt" dcl_id)
;check for errors

      );not

     (exit)
     ;if problem exit

);if
 
 (set_tile "sel1" SIZ)
 ;initilise list box

 (set_tile "sel2" SIZ1)
 ;initilise list box

 (start_list "sel1")
 ;start the list

 (mapcar 'add_list NAMES)
 ;add the bolt size

 (end_list)
 ;end the list

 (start_list "sel2")
 ;start the list

 (mapcar 'add_list LEN)
 ;add the lengths

 (end_list)
 ;end the list

 (cond
 ;on condition

((= gr "4,6") (set_tile "rb1" "1"))
;if GR 4,6 switch on radio button rb1

((= gr "8,8") (set_tile "rb2" "1"))
;if GR 8,8 switch on radio button rb2

((= gr "HSFG") (set_tile "rb3" "1"))
;if GR HSFG switch on radio button rb3

 );end cond

 (action_tile "rb1"
 ;if radio button rb1 selected

   	"(setq gr \"4,6\")"
;set grade of bolt

 );action_tile

 (action_tile "rb2"
 ;if radio button rb2 selected

   	"(setq gr \"8,8\")"
;set grade of bolt

 );action_tile

 (action_tile "rb3"
 ;if radio button rb3 selected

   	"(setq gr \"HSFG\")"
;set grade of bolt

 );action_tile

   (action_tile "cancel"	
   ;if cancel selected

	"(done_dialog)
;end dialog

 (setq userclick nil)"
 ;set flag to nill

   );action_tile
   ;if cancel set flag to nil

 (action_tile "accept"	
                                                ;why is this section in quotations?
 "(setq siz (get_tile \"sel1\"))           
 ;get the bolt size

 (setq siz1 (get_tile \"sel2\"))
 ;get the bolt length

 (done_dialog)
 ;end the dialog

 (setq userclick T)"
 ;set the flag to true

 );action tile

 (start_dialog)	
 ;start the dialogue

 (unload_dialog dcl_id)	
 ;unload the dialogue

  (if userclick	
  ;if OK has been selected

   (progn
   ;do the following

(setq NSIZ (cons 1000 SIZ))                       
;construct a new bolt size list

(setq NSIZ1 (cons 1000 SIZ1))
;construct a new bolt length list

(setq NGR (cons 1000 gr))
;construct a new bolt grade list

(setq e4 (chnitem NSIZ 2 e3))
;change the existing bolt size list

(setq e5 (chnitem NSIZ1 3 e4))
;change the existing bolt length list

(setq e6 (chnitem NGR 4 e5))
;change the existing bolt grade list

(setq e7 (subst e6 e3 e2))
;update list

(setq e8 (subst e7 e2 e))
;update list

(entmod e8)
;update the entity

    (setq SIZ (nth (atoi SIZ) NAMES))
    ;get the size of the bolt from the list

    (setq SIZ1 (nth (atoi SIZ1) LEN))
    ;get the length of the bolt from the list

    (alert (strcat "The size of bolt is " SIZ "\n"
    "The length of bolt is " SIZ1 "\n"
    "The grade of bolt is " GR)
    );alert


   );end progn

  );end if

(princ)
;finish cleanly

);end defun


;;This function replaces any element in a list with another element
;;It requires 3 parameters (chnitem value itemnumber list)

(defun chnitem (value num lst)                                  ;I understand what this codes urpose is
    (setq num (- num 1))					;but do not it is the most confusing to me
    (setq tmplt (list nil))
    (setq tmplt2 (list nil))
    (setq counter 0)
    (repeat  num
         (setq tmplt (append tmplt (list (nth counter lst))))
         (setq counter (+ counter 1))
    )
    (setq counter (+ counter 1))
    (repeat (- (length lst) (+ num 1))
         (setq tmplt2 (append tmplt2 (list (nth counter lst))))
         (setq counter (+ counter 1))
    )
    (setq tmplt (cdr tmplt))
    (setq tmplt2 (cdr tmplt2))
    (setq lst (append tmplt (list value) tmplt2))
)
(princ)
;load cleanly

Link to comment
Share on other sites

Below is a xdata example from Afralisp which would seem to be the starting point for your code

, the only lineyou need to change is (setq thedata '((-3 ("AFRALISP" (1000 . "Kenny is handsome") (1000 . "And intelligent"))))) where you would add your 9 values, also change AFRALISP to what you want your xata to be called.

 

I would also look at a library routine if you want a simple 9 line dcl I have one at home that makes as many entries as needed, I will post later. This only requires a couple of lines of code in your lisp as it writes the dcl to suit. There has been recently some posts about doing multi entry dcl's as a library routine.

 

Another important thing to remember about Xdata is that you can have more than one of the same associative code.
Let's attach some xdata to an entity in a drawing. Draw a line then type this:
(regapp "AFRALISP")
AutoLisp should return :
"AFRALISP"
You have now registered your external entity data name. This name is a unique identifier to your own extended entity data. Next we need to get the entity data list of the entity that we want to add exdata to. Type this :
(setq oldlist (entget (car (entsel)))) ; SINGLE ENTITY 
AutoLisp should return something like this :
Select object: ((-1 . <Entity name: 2100888>) (0 . "LINE") (5 . "271")
 (100 . "AcDbEntity") (67 . 0) (8 . "0") (100 . "AcDbLine") (10 336.561 591.45 0.0)
 (11 672.362 497.304 0.0) (210 0.0 0.0 1.0))
Now, let's create the exdata that we want to add to the entity :
(setq thedata '((-3 ("AFRALISP" (1000 . "Kenny is handsome") (1000 . "And intelligent")))))
Append it to the entity data list :
(setq newlist (append oldlist thedata))
Now, update the entity :
(entmod newlist)
We have now attached the xdata to the entity. To retrieve it we would type this :
(setq elist (entget (car (entsel)) '("AFRALISP")))
This would return the modified entity list. It should look something like this :
Select object: ((-1 . <Entity name: 2100888>) (0 . "LINE") (5 . "271")
 (100 . "AcDbEntity") (67 . 0) (8 . "0") (100 . "AcDbLine") (10 336.561 591.45 0.0)
 (11 672.362 497.304 0.0) (210 0.0 0.0 1.0) (-3 ("AFRALISP" (1000 . "Kenny is handsome")
 (1000 . "And intelligent"))))
To retrieve the xdata we would type this :
(setq exlist (assoc -3 elist))
This gets the xdata list from the entity list.
(-3 ("AFRALISP" (1000 . "Kenny is handsome") (1000 . "And intelligent")))
To retrieve the xdata itself we would type this :
(setq thexdata (car (cdr exlist)))
Now, we should have this :
("AFRALISP" (1000 . "Kenny is handsome") (1000 . "And intelligent"))
We now have an ordinary list. Because we created the xdata list, and we know in what order we created it, it's very simple to retrieve each individual part :
(setq data1 (cdr (nth 1 thexdata)))
(setq data2 (cdr (nth 2 thexdata)))
This should return :
"Kenny is handsome"
"And intelligent"

Link to comment
Share on other sites

This is not the how many dcl but rather a 1 2 or 3 entry it could be expanded to 9, but I would do it differently as I have already posted.

 

(if (not AH:getval3)(load "getvals3"))
(setq default1 "1" default2 "2" default "xx")
(ah:getval3 "Line 1" 5 4 default1 "Line2" 8 7 default2 "Line 3" 6 4 default)

 

; Input  Dialog box with variable title
; multiple lines of dcl input supported
; add extra lines if required by copying code defun
; By Alan H 2015
(vl-load-com)
; 1 line dcl
; sample code (ah:getval1 "Line 1" 5 4 defualt)
(defun AH:getval1 (title width limit def1 / fo fname)
; you can hard code a directory if you like for dcl file
;(setq fo (open (setq fname (vl-filename-mktemp "" "" ".dcl")) "w"))
(setq fo (open (setq fname "c:\\acadtemp\\getval.dcl") "w"))
(write-line "ddgetval : dialog {" fo)
(write-line " : row {" fo)
(write-line ": edit_box {" fo)
(write-line (strcat "    key = "  (chr 34) "key1" (chr 34) ";") fo)
(write-line  (strcat " label = "  (chr 34) title (chr 34) ";"  )   fo)
; these can be replaced with shorter value etc
(write-line (strcat "     edit_width = " (rtos width 2 0) ";" ) fo)
(write-line (strcat "     edit_limit = " (rtos limit 2 0) ";" ) fo)
(write-line "   is_enabled = true;" fo)
(write-line "    }" fo)
(write-line "  }" fo)
(write-line "ok_only;}" fo)
(close fo)
(setq dcl_id (load_dialog  fname))
; pt is a list 2 numbs -1 -1 centre ('(20 20))
;(not (new_dialog "test" dch "" *screenpoint*)) 
(if (not (new_dialog "ddgetval" dcl_id))
(exit))
(set_tile "key1" (setq val1 def1))
(action_tile "key1" "(setq val1 $value)")
(mode_tile "key1" 3)
(start_dialog)
(done_dialog)
(unload_dialog dcl_id)
; returns the value of val1 as a string
(vl-file-delete fname)
) ; defungetval1
; 2 line dcl
; sample code (ah:getval2 "Line 1" 5 4 default1 "Line2" 8 7 default2)
(defun AH:getval2 (title1 width1 limit1 def1 title2 width2 limit2 def2 / fo fname)
;(setq fo (open (setq fname "c:\\acadtemp\\getval.dcl") "w"))
(setq fo (open (setq fname (vl-filename-mktemp "" "" ".dcl")) "w"))
(write-line "ddgetval2 : dialog {" fo)
(write-line " : column {" fo)
(write-line ": edit_box {" fo)
(write-line (strcat "    key = " (chr 34) "key1" (chr 34) ";") fo)
(write-line  (strcat " label = "  (chr 34) title1 (chr 34) ";" ) fo)
(write-line (strcat "     edit_width = " (rtos width1 2 0) ";" ) fo)
(write-line (strcat "     edit_limit = " (rtos limit1 2 0) ";" ) fo)
(write-line "   is_enabled = true ;" fo)
(write-line "    }" fo)
(write-line "spacer_1 ;" fo)
(write-line ": edit_box {" fo)
(write-line (strcat "    key = " (chr 34) "key2" (chr 34) ";") fo)
(write-line (strcat " label = "  (chr 34) title2 (chr 34) ";"  ) fo)
(write-line (strcat "     edit_width = " (rtos width2 2 0) ";" ) fo)
(write-line (strcat "     edit_limit = " (rtos limit2 2 0) ";" ) fo)
(write-line "   is_enabled = true ;" fo)
(write-line "    }" fo)
(write-line "    }" fo)
(write-line "spacer_1 ;" fo)
(write-line "ok_only;}" fo)
(close fo)
; code part
(setq dcl_id (load_dialog  fname))
(if (not (new_dialog "ddgetval2" dcl_id))
(exit))
(mode_tile "key1" 3)
(set_tile "key1" (setq val1 def1))
(action_tile "key1" "(setq val1 $value)")
(mode_tile "key2" 3)
(set_tile "key2" (setq val2 def2))
(action_tile "key2" "(setq val2 $value)")
(start_dialog)
(done_dialog)
(unload_dialog dcl_id)
; returns the value of val1 and val2 as strings
(vl-file-delete fname)
) ; defungetval2
; sample code (ah:getval3 "Line 1" 5 4 default1 "Line2" 8 7 default2 "Line 3" 6 4 "123")
(defun AH:getval3 (title1 width1 limit1 def1 title2 width2 limit2 def2 title3 width3 limit3 def3 / fo fname)
;(setq fo (open (setq fname "c:\\acadtemp\\getval.dcl") "w"))
(setq fo (open (setq fname (vl-filename-mktemp "" "" ".dcl")) "w"))
(write-line "ddgetval3 : dialog {" fo)
(write-line " : column {" fo)
(write-line ": edit_box {" fo)
(write-line (strcat "    key = " (chr 34) "key1" (chr 34) ";") fo)
(write-line  (strcat " label = "  (chr 34) title1 (chr 34) ";" ) fo)
(write-line (strcat "     edit_width = " (rtos width1 2 0) ";" ) fo)
(write-line (strcat "     edit_limit = " (rtos limit1 2 0) ";" ) fo)
(write-line "   is_enabled = true ;" fo)
(write-line "    }" fo)
(write-line "spacer_1 ;" fo)
(write-line ": edit_box {" fo)
(write-line (strcat "    key = " (chr 34) "key2" (chr 34) ";") fo)
(write-line (strcat " label = "  (chr 34) title2 (chr 34) ";"  ) fo)
(write-line (strcat "     edit_width = " (rtos width2 2 0) ";" ) fo)
(write-line (strcat "     edit_limit = " (rtos limit2 2 0) ";" ) fo)
(write-line "   is_enabled = true ;" fo)
(write-line "    }" fo)
(write-line "spacer_1 ;" fo)
(write-line ": edit_box {" fo)
(write-line (strcat "    key = " (chr 34) "key3" (chr 34) ";") fo)
(write-line (strcat " label = "  (chr 34) title3 (chr 34) ";"  ) fo)
(write-line (strcat "     edit_width = " (rtos width3 2 0) ";" ) fo)
(write-line (strcat "     edit_limit = " (rtos limit3 2 0) ";" ) fo)
(write-line "   is_enabled = true ;" fo)
(write-line "    }" fo)
(write-line "    }" fo)
(write-line "spacer_1 ;" fo)
(write-line "ok_only;}" fo)
(close fo)
; code part
(setq dcl_id (load_dialog  fname))
(if (not (new_dialog "ddgetval3" dcl_id))
(exit))
(mode_tile "key1" 3)
(set_tile "key1" (setq val1 def1))
(action_tile "key1" "(setq val1 $value)")
(mode_tile "key2" 3)
(set_tile "key2" (setq val2 def2))
(action_tile "key2" "(setq val2 $value)")
(mode_tile "key3" 3)
(set_tile "key3" (setq val3 def3))
(action_tile "key3" "(setq val3 $value)")
(start_dialog)
(done_dialog)
(unload_dialog dcl_id)
; returns the value of val1 val2 and val3 as strings
(vl-file-delete fname)
) ; defungetval3

Link to comment
Share on other sites

Thanks but either I am not understanding your code (only been looking at lisp for about 3 weeks)

 

here is my modified code

 

(defun c:ENDT ( / )
;define function

(setvar "cmdecho" 0)
;switch off command echo

(prompt "\nSelect the Hole to Add/Modify Xdata : ")
;prompt the user

(setq e (entget (car (entsel)) '("AFRALISP")))
;get the associative code list

(setq e1 (assoc -3 e))
;get the xdata

(if (not e1)
;if there is no exdata

(progn
;do the following

(if (not (tblsearch "APPID" "AFRALISP"))
;check if the application has been registered
	
	(regapp "AFRALISP")
	;if not, register it

);if

	(setq e1 '(( -3 ("AFRALISP"
		  (1000 . "Description")
		  (1000 . "PartNumber")
		  (1000 . "Elevation")
		  
	))))
	;create a default xdata list
	
	(setq e (append e e1))
	;append to to the main list

	(entmod e)
	;modify the entity
	
);progn

);if

(setq e2 (assoc -3 e))
;get the code -3 list

(setq e3 (car (cdr e2)))
;get the exdata list

(setq PN (cdr (nth 1 e3)))
;get the partnumber index number

(setq EV (cdr (nth 2 e3)))
;get the elevation index number

(setq DS (cdr (nth 3 e3)))
;get the description index number

(setq userclick T)
;set flag

(setq PartNumber '(" "))
;Part Number Entry	

(setq Elevation '(" "))
;Elevation Value Entry

 	(setq Description '(" "))
;Description

(setq dcl_id (load_dialog "ENDT.dcl"))
;load dialogue

(if (not (new_dialog "ENDT" dcl_id)
;check for errors

      );not

     (exit)
     ;if problem exit

);if
 
 (set_tile "PN1" PN)
 ;initilise list box

 (set_tile "EV1" EV)
 ;initilise list box

 (set_tile "DS1" DS)
 ;initilise list box

 (start_list "PN1")
 ;start the list

 (mapcar 'add_list PartNumber)
 ;add the partnumber

 (end_list)
 ;end the list

 (start_list "EV1")
 ;start the list

 (mapcar 'add_list Elevation)
 ;add the elevation

 (start_list "DS1")
 ;start the list

 (mapcar 'add_list Description)
 ;add the description

 (end_list)
 ;end the list


;I commented out this next section because its not needed but I wanted to understand it later
;will delete it at completion - basically the origional template i used had radial buttons also
 
; (cond
 ;on condition
;	((= gr "4,6") (set_tile "rb1" "1"))
;	;if GR 4,6 switch on radio button rb1
;
;	((= gr "8,8") (set_tile "rb2" "1"))
;	;if GR 8,8 switch on radio button rb2
;
;	((= gr "HSFG") (set_tile "rb3" "1"))
;	;if GR HSFG switch on radio button rb3
;
; );end cond

;  (action_tile "rb1"
;  ;if radio button rb1 selected
;
;    	"(setq gr \"4,6\")"
;	;set grade of bolt
;
;  );action_tile
;
;  (action_tile "rb2"
 ;if radio button rb2 selected

;   	"(setq gr \"8,8\")"
;set grade of bolt

;  );action_tile

;  (action_tile "rb3"
 ;if radio button rb3 selected

;    	"(setq gr \"HSFG\")"
;set grade of bolt

; );action_tile

   (action_tile "cancel"	
   ;if cancel selected

	"(done_dialog)
;end dialog

 (setq userclick nil)"
 ;set flag to nill

   );action_tile
   ;if cancel set flag to nil

(action_tile "accept"	

 "(setq PN (get_tile \"PN1\"))
 
 (setq EV (get_tile \"EV1\"))
 
 (setq DS (get_tile \"DS1\"))
 
 (done_dialog)
 
 (setq userclick T)"
 ;set the flag to true

);action tile

 (start_dialog)	
 ;start the dialogue

 (unload_dialog dcl_id)	
 ;unload the dialogue

  (if userclick	
  ;if OK has been selected

   (progn
   ;do the following

(setq NPN (cons 1000 PN))
;construct a new part number  list

(setq NEV (cons 1000 EV))
       ;construct a new elevation list

(setq NDS (cons 1000 DS))
;construct a new description list

(setq e4 (chnitem NPN 2 e3))
;change the Partnumber list

(setq e5 (chnitem NEV 3 e4))
;change the elevation list

(setq e6 (chnitem NDS 4 e5))
;change the Description list

(setq e7 (subst e6 e3 e2))
;update list

(setq e8 (subst e7 e2 e))
;update list

(entmod e8)
;update the entity

    (setq PN (nth (atoi PN) PartNumber))
    ;get the Part Number from the list

   (setq EV (nth (atoi EV) Elevation))
    ;get the elevation from list
     
   (setq DS (nth (atoi DS) Description)) 
    ;get the Description from the list

     (alert (strcat "The Part Number is " PN "\n"
    "The Elevation is " EV "\n"
    "The Description is " DS)
    );alert


   );end progn

  );end if

(princ)
;finish cleanly

);end defun


;;This function replaces any element in a list with another element
;;It requires 3 parameters (chnitem value itemnumber list)

(defun chnitem (value num lst)
    (setq num (- num 1))
    (setq tmplt (list nil))
    (setq tmplt2 (list nil))
    (setq counter 0)
    (repeat  num
         (setq tmplt (append tmplt (list (nth counter lst))))
         (setq counter (+ counter 1))
    )
    (setq counter (+ counter 1))
    (repeat (- (length lst) (+ num 1))
         (setq tmplt2 (append tmplt2 (list (nth counter lst))))
         (setq counter (+ counter 1))
    )
    (setq tmplt (cdr tmplt))
    (setq tmplt2 (cdr tmplt2))
    (setq lst (append tmplt (list value) tmplt2))
)
(
princ)
;load cleanly

 

I always get this "bad DXF group: (-3 ("AFRALISP" (1000) (1000) (1000)))" error - I imagine it has something to do with the fact that I need to use edit_box where the template uses popup_list?

Link to comment
Share on other sites

Still cant quite get what I'm looking for - If anyone could look at the code above this and maybe critique it or help me out a bit that would be great.

 

Thanks - back to the drawing board,

 

Brian

Link to comment
Share on other sites

Its kinda confusing what are your intentions, since you are talking about a project in Visual LISP, but the actual code uses Vanilla LISP to manipulate the Xdata inside the DXF list of a certain ename.

Also theres DCL coding, which would additionally confuse you - afterall you mentioned that you are "amateur programmer and novice autocad user".

 

So what are your intentions?:

  • A. Working with xdata using vanilla lisp (requires dxf list manipulation) Example
  • B. Working with xdata using visual lisp (GetXdata/SetXdata methods) Example
  • C. Using DCL with lisp - Start from here.

Link to comment
Share on other sites

Like Grr your example dcl is 3 lines but your post says you want 9 items, if you post a dwg with say a line the 9 items as text or are they other object properties or a mix, try and give us a picture of what you want hand draw the dcl with the labels.

 

You are not asking for anything to hard its easier for us to start again than try to patch your code.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...