Jump to content

AUTOLISP Find block by TAG1 Value and Change An attribute


Recommended Posts

Posted

So I'm trying to use Lee Mac's LISP function here:

http://www.cadtutor.net/forum/showthread.php?84816-Find-and-Select-blocks-that-have-certain-attributes-via-command-line

 

What I need to do is:

I have a block with

- Block Name = "VIFCD_001"

- Attribute = "TAG1" Value = "-M161"

** The Value of Attribute TAG1 is always unique, however there could be multiple VIFCD_001 blocks, each with different TAG1 values**

 

I need a LISP routine that finds the block Where TAG1= and then change the attribute "DESC" of that specific block to

 

Lee's LISP function is able to select the block by tag name which is great, but I can't seem to figure out how to tell it to then look for the DESC attribute in that block and change the value.

 

(defun c:setAttrVals (tagName descName)

.....

.....

....

(princ)

)

 

 

Can anyone help?

Posted

You would start by pick block and get its name a more universal approach, then make a selection of all blocks with that name, then go through all those blocks checking attribute Tagname=TAG1 then look at the value and change it. For a do all style approach I have been lately using the attribute position rather than a tag name required this works for any block name.

 

Try this

(defun c:test ( / oldtag1 obj bname newstr)
(setq oldtag1 "TAG1") ; attribute tag name

(setq obj (vlax-ename->vla-object (car (entsel "\nPick object"))))
(setq bname (vla-get-name obj)) ; block name need a check for picked a block

(setq ss (ssget "x"  (list (cons 0  "INSERT") (cons 2 bname))))
(princ "\n")
(setq newstr (getstring "Please enter new value"))
(setq x (sslength ss))

(foreach att (vlax-invoke (vlax-ename->vla-object (ssname SS (setq x (- x 1)) )) 'getattributes)
(if (= oldtag1 (strcase (vla-get-tagstring att)))
(vla-put-textstring att newstr) 
) ; end if
) ; foreach
)

Posted

Consider the following code:

(defun c:doit ( / bln des ent enx flg fnd idx new sel tag )
   (setq
       bln "VIFCD_001"
       tag "DESC"
   )
   (if (setq sel (ssget "_X" (list '(0 . "INSERT") '(66 . 1) (cons 2 bln))))
       (progn
           (setq fnd (strcase (getstring t "\nSpecify attribute value to find: "))
                 new (cons  1 (getstring t (strcat "\nSpecify new value for \"" tag "\" attribute: ")))
           )
           (repeat (setq idx (sslength sel))
               (setq ent (entnext (ssname sel (setq idx (1- idx))))
                     enx (entget ent)
                     des nil
                     flg nil
               )
               (while (= "ATTRIB" (cdr (assoc 0 enx)))
                   (cond
                       (   (= tag (strcase (cdr (assoc 2 enx))))
                           (setq des enx)
                       )
                       (   (or flg (setq flg (wcmatch (strcase (cdr (assoc 1 enx))) fnd))))
                   )
                   (setq ent (entnext ent)
                         enx (entget  ent)
                   )
               )
               (if (and des flg)
                   (if (entmod (subst new (assoc 1 des) des))
                       (entupd (cdr (assoc -1 des)))
                   )
               )
           )
       )
       (princ (strcat "\nNo blocks called \"" bln "\" found in the active drawing."))
   )
   (princ)
)

Posted

Lee, why don't you use the 'flg' variable to replicate (vl-some) when iterating thru the attribs, using the (while) loop:

 

(while (and (= "ATTRIB" (cdr (assoc 0 enx))) (not flg) )
 ...
); while

Posted
Lee, why don't you use the 'flg' variable to replicate (vl-some) when iterating thru the attribs, using the (while) loop:

 

(while (and (= "ATTRIB" (cdr (assoc 0 enx))) (not flg) )
 ...
); while

 

What if the wcmatch expression is validated before the 'tag' attribute is encountered? ;)

Posted
What if the wcmatch expression is validated before the 'tag' attribute is encountered? ;)

 

Ahh I see now, didn't read carefully what the task was = misunderstood the coding.

 

FWIW, heres another approach (copied the user-prompts from you) :

 

(defun C:test ( / bnm tag n SS fnd new i o L )
 
 (setq
   bnm "VIFCD_001"
   tag "DESC"
 )
 
 (and
   (setq n (_AttdefPosition bnm tag))
   (setq SS (ssget "_X" (list '(0 . "INSERT") '(66 . 1) (cons 2 (strcat "`**," bnm)))))
   (setq fnd (strcase (getstring t "\nSpecify attribute value to find: ")))
   (setq new (getstring t (strcat "\nSpecify new value for \"" tag "\" attribute: ")))
   (repeat (setq i (sslength SS))
     (and 
       (eq bnm (vla-get-EffectiveName (setq o (vlax-ename->vla-object (ssname SS (setq i (1- i)))))))
       (setq L (vlax-invoke o 'GetAttributes))
       (vl-some (function (lambda (x) (wcmatch (strcase (vla-get-TextString x)) fnd))) L)
       (vla-put-TextString (nth n L) new)
     )
   )
 )
 (princ)
); defun C:test

(defun _AttdefPosition ( bnm tgnm / e i enx f )
 (and
   (setq e (tblobjname "BLOCK" bnm))
   (setq e (cdr (assoc -2 (entget e))))
   (setq i -1)
   (while (and e (not f))
     (setq enx (entget e)) (setq e (entnext e))
     (and (member '(0 . "ATTDEF") enx) (setq i (1+ i)))
     (setq f (member (cons 2 tgnm) enx))
     (and (member '(0 . "SEQEND") enx) (setq e nil))
   )
 )
 (if f i)
); defun _AttdefPosition

 

I saw you tried to limit up to only one iteration while processing the attributes, its obvious you like to think out such clever methods. :thumbsup:

Posted
FWIW, heres another approach:
< ... >

 

I would recommend not relying upon the order in which attribute definitions are encountered in the block definition corresponding to the order in which attribute references are encountered in each block reference, as it is possible to generate attribute references independently of the block definition, hence one cannot guarantee that the two will be entirely consistent. When working with attributes, it is almost always better to differentiate the attributes using their attribute tags (unless you are forced into an alternative, for example, if duplicate tags have been used - IMO, AutoCAD should prevent this from happening).

 

I saw you tried to limit up to only one iteration while processing the attributes, its obvious you like to think out such clever methods. :thumbsup:

 

Thanks - though, it is always worth striking a balance between efficiency & readability: ruthlessly efficient code can become incredibly unreadable and therefore difficult to maintain in a general application.

Posted

FWIW, if you wanted to use vl-some to limit the iteration, here's another approach:

(defun c:doit ( / bln dsc flg fnd idx new sel tag )
   (setq
       bln "VIFCD_001"
       tag "DESC"
   )
   (if (setq sel (ssget "_X" (list '(0 . "INSERT") '(66 . 1) (cons 2 bln))))
       (progn
           (setq fnd (strcase (getstring t "\nSpecify attribute value to find: "))
                 new (getstring t (strcat "\nSpecify new value for \"" tag "\" attribute: "))
           )
           (repeat (setq idx (sslength sel))
               (if (vl-some
                      '(lambda ( att )
                           (or flg (setq flg (wcmatch (strcase (vla-get-textstring att)) fnd)))
                           (or dsc (if (= tag (strcase (vla-get-tagstring att))) (setq dsc att)))
                           (and flg dsc)
                       )
                       (vlax-invoke (vlax-ename->vla-object (ssname sel (setq idx (1- idx)))) 'getattributes)
                   )
                   (vla-put-textstring dsc new)
               )
               (setq flg nil dsc nil)
           )
       )
       (princ (strcat "\nNo blocks called \"" bln "\" found in the active drawing."))
   )
   (princ)
)
(vl-load-com) (princ)

Posted
I would recommend not relying upon the order in which attribute definitions are encountered in the block definition corresponding to the order in which attribute references are encountered in each block reference, as it is possible to generate attribute references independently of the block definition, hence one cannot guarantee that the two will be entirely consistent.

 

Thanks Lee - I wanted to hear your oppinion about that (experiment) code I posted, as I don't have that much of experience, although I'd usually go straight with the TagString comparsion approach on the attribute references.

 

 

When working with attributes, it is almost always better to differentiate the attributes using their attribute tags (unless you are forced into an alternative, for example, if duplicate tags have been used - IMO, AutoCAD should prevent this from happening).

 

Ahh yes, I've forgot about that - before I was iterating over all attribute references, until I learned how to use (vl-some) and forgot about the possibility of duplicate tags.

Now I understand why you decided to process all attribs per block.

 

 

 

Thanks - though, it is always worth striking a balance between efficiency & readability: ruthlessly efficient code can become incredibly unreadable and therefore difficult to maintain in a general application.

 

I agree on that, unless that code is used as a subfunction, so you just need to know what are gonna be your inputs in it and what should be returned.

Then one can save the debugging headaches, by parsing inputs. i.e.:

 

(setq elephant (cow->elephant (sheep->cow (dog->sheep (cat->dog (mouse->cat (fly->mouse fly)))))))

 

I'm just leaving my oppinion to the one who reads this (not trying to tutor you :lol: ).

 

 

FWIW, if you wanted to use vl-some to limit the iteration, here's another approach:
<...>

 

Thanks for posting your suggestion with (vl-some) - it shall boggle a few brains, that are trying to learn something new.

I liked this lambda part you did:

 

'(lambda ( att )
 (or flg (setq flg (wcmatch (strcase (vla-get-textstring att)) fnd)))
 (or dsc (if (= tag (strcase (vla-get-tagstring att))) (setq dsc att)))
 (and flg dsc)
)

 

It seems very handy method to limit the iteration if there are multiple requirements for different items.

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...