Update all values of known attributes.

Update all values of known attributes.

Anonymous
Not applicable
1,037 Views
12 Replies
Message 1 of 13

Update all values of known attributes.

Anonymous
Not applicable

AutoCAD Mechanical 2019

I have several drawing border blocks (different sizes) they use the same named attributes.   DWG_NO, DESC, ECN, and REV.  We have been using some various lisp programs out there to change these attributes but most require selecting the border to get the attribute tag and value.   I know the tag and the value is being pulled from a environment variable so I do not need retrieved those, I only need to plug in the values to all the tags for all the blocks.  

 

(defun c:popatt (/dwgno desc1 ecn1 rev1)
(setq dwgno "12345")
(setq desc1 "MY DWG")
(setq ecn1 "4321")
(setq rev1 "B")

;block attribute tags for all blocks
; DWG_NO
; DESC
; ECN
; REV


;program that needs help
(vla-put-textstring DWG_NO dwgno)
(vla-put-textstring DESC desc1)
(vla-put-textstring ECN ecn1)
(vla-put-textstring REV rev1)
(do for all blocks)


); end
0 Likes
Accepted solutions (1)
1,038 Views
12 Replies
Replies (12)
Message 2 of 13

pbejse
Mentor
Mentor

@Anonymous wrote:

AutoCAD Mechanical 2019

, I only need to plug in the values to all the tags for all the blocks.  

 


If the tag names  and the corresponding values are known then YES i can be easily done using a association list

(defun c:demo ( / ss i e foundTagMatch)
  (if (setq ss (ssget '((0 . "INSERT")(66 . 1))))
    (repeat (setq i (sslength ss))
      	(setq e (vlax-ename->vla-object (ssname ss (Setq i (1- i)))))
      	(foreach itm (vlax-invoke e 'GetAttributes)
	  (if (setq foundTagMatch (assoc (strcase (Vla-get-tagstring itm))
					 '(("DWG_NO" . "12345")
					   ("DESC" . "MY DWG")
					   ("ECN" . "4321")
					   ("REV" . "B")
					   )
					 )
		    )
	    (Vla-put-textstring itm (cdr foundTagMatch)))
	  )
      )
    )(princ)
  )

Holler if you need help in putting this together to work on your drawings

 

HTH

 

Message 3 of 13

Anonymous
Not applicable

This works but I am trying to avoid having to select the block.  The tag names are known and the values are retrieved from a ENV Variable.  I am trying a little bit different route and that is to make a dotted pair of the tag and the value.  With this I think I can then just populate the values like the last section of your code.

(defun c:popatt (/tag val)
; block tags
(setq tag '("DWG_NO" "DESC" "ECN" "REV"))
;tag values
(setq val '("12345" "MY DWG" "4321" "B")); simple given values for now

;the part I need help with to make dotted list
(setq newlist ?????)
; result of this new list would be
; (("DWG_NO" . "12345") ("DESC" . "MY DWG") ("ECN" . "4321") ("REV" . "B"))

; Then I think I can do something like this
(setq Tag (assoc (vla-get-TagString val) newlist))
(vla-put-TextString val (cdr tag))
)

 

0 Likes
Message 4 of 13

pbejse
Mentor
Mentor

@Anonymous wrote:

This works but I am trying to avoid having to select the block.  The tag names are known and the values are retrieved from a ENV Variable.  I am trying a little bit different route and that is to make a dotted pair of the tag and the value.  With this I think I can then just populate the values like the last section of your code.

(setq tag '("DWG_NO" "DESC" "ECN" "REV"))
(setq val '("12345" "MY DWG" "4321" "B")); simple given values for now

If you want automagic selection

 

 (setq ss (ssget "X" '((0 . "INSERT")(66 . 1))))

 

And here's how you make an a dotted pair off that two variables

 

(setq tag '("DWG_NO" "DESC" "ECN" "REV"))
(setq val '("12345" "MY DWG" "4321" "B"))

 

 

(mapcar 'cons tag val)
(("DWG_NO" . "12345") ("DESC" . "MY DWG") ("ECN" . "4321") ("REV" . "B")) 

 

 HTH

 

Message 5 of 13

Anonymous
Not applicable

So I was able to make the dotted pair but I'm not able to replace the tag values in the block.  I think because I am not using the code from "ssget" to "GetAttributes" , this part of the code defines info to be used in the last part specifically "itm" value and then each value linked to the others.  I was as thinking I can make a dotted pair because when you do "getattributes" this is the format of that list.  The dotted pair would be the known tags with the given values, then this list replaces the values in the block tags using vla-put-TextString some how.  But vla-put-TextString uses "itm" which looks to "e" and serval other values.  Can "itm" look to this new dotted pair? Like this?

(setq tag '("DWG_NO" "DESC" "ECN" "REV"))
(setq val '("12345" "MY DWG" "4321" "B"))
   (foreach itm (mapcar 'cons tag val)
	  (if (setq foundTagMatch (assoc (strcase (Vla-get-tagstring itm))
	    '(("DWG_NO." . "12345")
	     ("DESCRIPTION" . "MY DWG")
	     ("ECN_NO." . "4321")
	      ("REV" . "B")
	)
	)
	 )
	    (Vla-put-textstring itm (cdr foundTagMatch)))
	  )

 

0 Likes
Message 6 of 13

Anonymous
Not applicable

So I just thought, how can to I replace values in the dotted pair list?

Current dotted pair list.

(("DWG_NO" . "12345") ("DESC" . "MY DWG") ("ECN" . "4321") ("REV" . "B"))

 

 New dotted pair list using different values.   

 

; new values
(setq vals '("5678" "YOUR DWG" "9876" "Z")

;updated dotted pair
(("DWG_NO" . "5678") ("DESC" . "YOUR DWG") ("ECN" . "9876") ("REV" . "Z"))

 

0 Likes
Message 7 of 13

pbejse
Mentor
Mentor

@Anonymous wrote:

So I was able to make the dotted pair but I'm not able to replace the tag values in the block. ...

It's good to know that you're trying to learn @Anonymous 

There is nothing inside the foreach statement that refers to a defined attribute objects.

 

This created the dotted pair --> (mapcar 'cons tag val) .The value of itm in each loop will be from that list.

as a dotted pair--> ("DWG_NO" . "12345") and not an  attribute definition as you attempted to do here

(Vla-get-tagstring itm) [<-- that caused an error " ; error: bad argument type: VLA-OBJECT ("DWG_NO" . "12345")]

 

From my example, the items to be process is this --> (vlax-invoke e 'GetAttributes), that line retrieves the attribute defintion of the block in a form of a list.

 

So you are right when you say 

 

I think because I am not using the code from "ssget" to "GetAttributes" ,

The dotted pair is the list of TAG as a key  and its corresponding value. You still need the object to where the values would go after a successful match is found.

 

Look at the code at post # 2. and go at it again. You can do it.

Message 8 of 13

Anonymous
Not applicable
Accepted solution

@pbejse 

Thanks for your help, I got it working like I want. 

(defun c:demo3 ( / tag val newlist ss i e foundTagMatch)

(setq tag '("DWG_NO." "DESCRIPTION" "ECN_NO." "REV"))
(setq val '("12345" "MY DWG" "4321" "B"))
(setq newlist (mapcar 'cons tag val))


  (if (setq ss (ssget "X" '((0 . "INSERT")(66 . 1))))  
    (repeat (setq i (sslength ss))
      	(setq e (vlax-ename->vla-object (ssname ss (Setq i (1- i)))))
      	(foreach itm (vlax-invoke e 'GetAttributes)
	  (if (setq foundTagMatch (assoc (strcase (Vla-get-tagstring itm))
					 newlist
					 )
		    )
	    (Vla-put-textstring itm (cdr foundTagMatch)))
	  )
      )
    )(princ)
  )
0 Likes
Message 9 of 13

Anonymous
Not applicable

@pbejse 

Ok don't laugh, this does what I needs but can it be simplified.  Each name is a variable that I set earlier.  It gives me the list I need but man there has to something more simple. 

 

(setq val (cons ecnno
	   (cons  model_rev
	    (cons model_number 
	     (cons model_description 
	      (cons reviewedby 
	       (cons review_date 
	        (cons mfg_reviewer
                 (cons mfg_review_date							 
                  (list approvedby  approve_date)
                 )
                )
               )
              )
             )
            )
           )
          )
0 Likes
Message 10 of 13

Anonymous
Not applicable

This is the code I've been using for years to update block attributes (tags) in batch.

 

The nice thing about this is that you don't need to know the current value, it works by providing the block name, the attribute (tag) name, and the value you want to place in it. If there are multiple of the same blocks in the drawing it will change all of them, although it could be customized to act differently.

 

 

; Original Source: https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/lisp-to-change-a-specific-attribute-from-a-specific-block-to-a/td-p/3254566
;
; Example call
;	(UpdateBlockAttribute "Name of block here" "Name of Attribute (Tag) here" "Value to set attribute here")
;
;
(defun UpdateBlockAttribute (bn Tg Tv / aDoc ss)
	(vl-load-com)
	(setq aDoc (vla-get-ActiveDocument (vlax-get-acad-object)))
	(cond
		((and
				(ssget "_x" (list '(0 . "INSERT") (cons 2 (strcat bn ",`*U*"))))
				(vlax-for
					itm (setq ss (vla-get-ActiveSelectionSet aDoc))
					(if (and
							(eq (strcase (vla-get-EffectiveName itm)) (strcase bn))
							(setq itm (assoc
								(strcase tg)
									(mapcar (function (lambda (j) (list (vla-get-tagstring j) (vla-get-textstring j) j)
											)
										)
									(vlax-invoke itm 'GetAttributes)
									)
								)
							)
							)(vla-put-textstring (last itm) tv)
					)
				)
			(vla-delete ss)
			)
		)
	)
)

 

 

0 Likes
Message 11 of 13

pbejse
Mentor
Mentor

@Anonymous wrote:

 

Ok don't laugh, this does what I needs but can it be simplified.  Each name is a variable that I set earlier.  It gives me the list I need but man there has to something more simple. 


 

What ever that us, please never do that again [ and I'm not laughing ]

oh wait ..

 Lol.png

 

But seriously, Not sure what you're intending to do but all that is basically this without the unnecessary cons

(setq val (list ecnno model_rev model_number model_description
	      reviewedby review_date mfg_reviewer mfg_review_date
	      approvedby approve_date
	     )
)

Tell us more about this @Anonymous 

 

Message 12 of 13

pbejse
Mentor
Mentor

@Anonymous wrote:

This is the code I've been using for years to update block attributes (tags) in batch.

The nice thing about this is that you don't need to know the current value,...

 

Wish I could come up with something like that @Anonymous  😄

 

0 Likes
Message 13 of 13

Anonymous
Not applicable

@pbejse 

Information from Teamcenter (ECN, Reviewer, REV, etc) is pushed to AutoCAD Environment (shell).  The goal was to use this information to populate the title block automagically while publisher lisp is running.  I made  a program to do this but it would not update the one multi-text attribute in the block with out longer code.   

The cons thing was all the variables to be put in a list to combine with the tags. 

The values are retrieved from getenv and stored as another variable. 

(if(/= (getenv "ECN_NUMB") nil)(setq ecnno (strcase (getenv "ECN_NUMB"))))

 

 

0 Likes