Store List in Dictionary / Xrecord

Store List in Dictionary / Xrecord

CodeDing
Advisor Advisor
2,549 Views
8 Replies
Message 1 of 9

Store List in Dictionary / Xrecord

CodeDing
Advisor
Advisor

Hello,

 

Whew, it's been just over a year using LISP, but I'm finally getting into trying to make a decent application.

 

I am struggling with trying to trying to save a list of entity handles into an Xrecord. I have not been able to find a good example yet. I need some help.

 

Essentially I have 1 - 50+ entities that make up an object. I do not want to create a block with these entities because editing them would not work efficiently. Therefore, I would like to save a list of their handles (In Order!) in an Xrecord, so that I can reference this inside my custom dictionary next time the dwg is opened.

 

Any insight on the matter is appreciated. Here's what I have so far:

(defun c:TEST ( / myD myX)
(setq myD (DictCheck))
(setq myX (AddXrec myD))
;Do More Stuff
(princ)
);defun

(defun DictCheck ( / return)
;tests if dictionary exists, if not creates it
(if (not (setq return (dictsearch (namedobjdict) "MY_DICT")))
  (setq return (dictadd (namedobjdict) "MY_DICT" (entmakex '((0 . "DICTIONARY") (100 . "AcDbDictionary")))))
  (setq return (cdr (assoc -1 return)))
);if
);defun

(defun AddXrec (dict / return x)
(if (not (setq return (dictsearch dict "MY_XREC")))
  (progn
    (setq x (entmakex '((0 . "XRECORD")
			(100 . "AcDbXrecord")
			;Enter list here (maybe pass list into function?)
			;(list h1 h2 h3 h4 h5)
			)));setq
    (setq return (dictadd dict "MY_XREC" x))
  );progn
;else
  (setq return (cdr (assoc -1 return)))
);if
);defun

Best,

~DD

0 Likes
Accepted solutions (2)
2,550 Views
8 Replies
Replies (8)
Message 2 of 9

scot-65
Advisor
Advisor
I have not used the dictionaries / xrecords method for quite a while
ever since I started using VLAX-LDATA-PUT and VLAX-LDATA-GET.

List (of handles) can be stored there much easier than DICTADD
and accessing is similar to DICTSEARCH...

And VLAX-LDATA-DELETE is easy to find and execute...

???

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

0 Likes
Message 3 of 9

CodeDing
Advisor
Advisor

@scot-65,

 

Thank you for the input. I looked into LDATA before starting and have chosen not to use that route for storing items.

 

Best,

~DD

0 Likes
Message 4 of 9

doaiena
Collaborator
Collaborator
Accepted solution

I would much rather use visual lisp to interact with Xrecords, i find it more intuitive to use in such cases.

 

In your initial post, you have said you only want to store entity handles in a dictionary, so i have prepared a demo for you, that stores the entity handles of selected objects in a dictionary.

 

I didn't add any error checking to the code, but it is mandatory that you do so / "vl-catch-all-apply" and "vl-catch-all-error-p" need to be added in some places to make the code "foolproof" /.

I didn't comment the code very heavily, so feel free to ask any questions you may have about the logic, if you have any.

 
EDIT:
I noticed there was an error in my "AddXRec" function. I have added a counter now and it should work as intended.

 

(vl-load-com)

;Test function to store the selected entities' handles under an Xrecord named MY_XREC
;inside a Dictionary named MY_DICT
(defun c:Test ( / ss ctr handles dataTypes)

(if (setq ss (ssget))
(progn

(setq ctr 0)
(repeat (sslength ss)

(setq handles (cons (cdr (assoc 5 (entget (ssname ss ctr)))) handles))
(setq dataTypes (cons 1 dataTypes))
(setq ctr (1+ ctr))
);repeat

(AddXRec (GetOrCreateDict "MY_DICT") "MY_XREC" dataTypes handles)

(foreach handle (GETXREC (GetOrCreateDict "MY_DICT") "MY_XREC")
(princ (strcat "\n" handle))
)

));if ss

(princ)
);defun




;Get a Dictionary object if it exists, if not create it
(defun GetOrCreateDict ( dictName / )
(if (vl-catch-all-error-p (vl-catch-all-apply 'vla-item (list (vla-get-Dictionaries (vla-get-activedocument (vlax-get-acad-object))) dictName)))
(vla-Add (vla-get-Dictionaries (vla-get-activedocument (vlax-get-acad-object))) dictName)
;else
(vla-Item (vla-get-Dictionaries (vla-get-activedocument (vlax-get-acad-object))) dictName)
);if
);defun




;Add Data to Xrecord and Dictionary of your choice
(defun AddXRec ( dictName xRecName dTypeLst dataLst / dataType data ctr)

(setq dataType (vlax-make-safearray vlax-vbInteger (cons 1 (length dTypeLst))))
(setq data (vlax-make-safearray vlax-vbVariant (cons 1 (length dataLst))))

(setq ctr 1) (mapcar '(lambda (dType dat) (vlax-safearray-put-element dataType ctr dType) (vlax-safearray-put-element data ctr dat)
(setq ctr (1+ ctr)) ) dTypeLst dataLst ) (vla-SetXRecordData (vla-AddXRecord dictName xRecName) dataType data) );defun ;Get Data from Xrecord and Dictionary of your choice (defun GetXRec ( dictName xRecName / dType data) (vla-GetXRecordData (vla-item dictName xRecName) 'dType 'data) (mapcar '(lambda (x) (variant-value x)) (vlax-safearray->list data)) );defun

 

Message 5 of 9

CodeDing
Advisor
Advisor

@doaiena,

 

Although I do prefer the AutoLISP method, I tried your provided code on 2 entities then checked the Xrecord to see how the data was stored:

 

((-1 . <Entity name: 2ccc1cf6dd0>)
(0 . "XRECORD")
(5 . "B65D5")
(102 . "{ACAD_REACTORS")
(330 . <Entity name: 2ccc1cf6dc0>)
(102 . "}")
(330 . <Entity name: 2ccc1cf6dc0>)
(100 . "AcDbXrecord")
(280 . 1)
(1 . "AF6B3") <--handle
(1 . "AF6CB"))<--handle

...it looks as though the handles are merely stored in 2 separate DXF 1 codes, Primary text strings.

 

...Is there no method, other than LDATA, for me to store an organized list? I am worried that If I store an organized list as all separate DXF 1 codes, then they may not be in that same order every time the dwg is opened.

 

Any feedback on this matter?

 

Best,

~DD

0 Likes
Message 6 of 9

doaiena
Collaborator
Collaborator

You can store whatever data you want in any order you want. If you provide me with sample data, structured and ordered the way you would like to be stored in the dictionary, i'll edit the code to provide that output. The code i wrote was just an example of how you can store data inside a dictionary. It wasn't structured in any particular way. The order of the items can't change on its own, and you are actually storing an array inside the dictionary, not a list.

0 Likes
Message 7 of 9

CodeDing
Advisor
Advisor

@doaiena,

 

Thank you for the feedback.

So, based on your response is it fair to say that I can add n number of handles to my Xrecord as DXF 1 codes and, as long as I entered them in a correct order, they will always return in the same order if I were to retrieve my Xrecord?

Like such.. using my original code?

    (setq l (list "h1" "h2" "h3" "h4" "h5"))
    (setq x (entmakex (append (list (cons 0 "XRECORD")
				    (cons 100 "AcDbXrecord"))
			      (mapcar (function (lambda (h) (cons 1 h))) l))))

This stores the handles as separate DXF 1 codes and returns this from the Xrecord:

((-1 . <Entity name: 24a6c1b2c90>)
  (0 . "XRECORD")
  (5 . "8621")
  (102 . "{ACAD_REACTORS")
  (330 . <Entity name: 24a6c1b2c80>)
  (102 . "}")
  (330 . <Entity name: 24a6c1b2c80>)
  (100 . "AcDbXrecord")
  (280 . 1)
  (1 . "h1") (1 . "h2") (1 . "h3") (1 . "h4") (1 . "h5"))

...I am just wanting to be VERY SURE that this order can be maintained EVERY TIME after the dwg has been closed then re-opened?

Best,

~DD

0 Likes
Message 8 of 9

doaiena
Collaborator
Collaborator
Accepted solution

To my knowledge, an Xrecord's data can't be reordered with the opening and closing of a drawing.

On another note, you don't have to use DXF 1 code. Xrecodrs allow for a wide range of codes to be used. I just hapened to use 1 in my code. You should check AutoCAD's documentation for more information on which codes are available.

Message 9 of 9

CodeDing
Advisor
Advisor

I have the DXF code documentation. You've been a great help.

Thanks,

~DD

0 Likes