Jump to content

Recommended Posts

Posted

Hello everyone!

 

I hope someone can take a minute or two to help me out with my question. I'm looking to write a lisp for various functions and I need to get a value of a specific attribute in a block that I would have to select.

 

All I need is to store the value in a setq "attval" so that I can reuse that value over and over in my lisps.

 

How would I go about defining this setq after I select a block? Lets say the attribute name in the block (there are many attributes) is called "Title".

 

I'm pretty sure this can be done as I've seen some examples on this forum, but all the lisps I've seen so far incorporate other functions that I don't need and I can't figure out the exact string I need to do what I'm looking for.

 

Any help would be appreciated!

 

Thanks

Posted

You could approach this in one of two ways, either through Vanilla AutoLISP or through Visual LISP, I'll show you both.

 

Firstly, we need to get a block to work with, for this we can use entsel.

 

(setq bEnt (car (entsel "\nSelect Block: ")))

Notice I use 'car' to retrieve the entity name, as entsel will return a two element list upon a successful pick, the first item being the entity name of the object picked and the second item being the point at the center of the aperture that was picked.

 

We would also need to check that the entity picked is indeed a block, and that it has attributes:

 

(if
 (and
   (setq bEnt (car (entsel "\nSelect Block: ")))
   (eq "INSERT" (cdr (assoc 0 (entget bEnt))))
   (= 1 (cdr (assoc 66 (entget bEnt))))
 )

This is how I might start the code, using an IF statement to make sure that the user picks an entity and that the entity picked is indeed an attributed block.

 

For more reference on the DXF codes used, see here.

 

Ok, so now that we have our block we can iterate through its attributes, the attributes can be found by using entnext on the INSERT entity name.

 

We can iterate through all the attributes in this way, by using entnext on the previous attribute entity encountered. When we reach a 'SEQEND' entity, we have iterated through all the attributes that the block contains (we can then get back to the parent block entity using DXF -2 on the SEQEND entity).

 

In code, we can concisely write this as:

 

(while
 (not
   (eq "SEQEND"
     (cdr
       (assoc 0
         (entget
           (setq bEnt
             (entnext bEnt)
           )
         )
       )
     )
   )
 )

 ...
 
)

In this way, the WHILE loop will continue until the SEQEND entity is reached. Notice that we also set the variable 'bEnt' to itself each time so that we are using entnext on the previous subentity retrieved.

 

In the loop we can now operate on our attributes, for example retrieving the value of attribute with tag 'TAG':

 

(while
 (not
   (eq "SEQEND"
     (cdr
       (assoc 0
         (entget
           (setq bEnt
             (entnext bEnt)
           )
         )
       )
     )
   )
 )

 (if (eq "TAG" (cdr (assoc 2 (entget bEnt))))

   (setq AttVal (cdr (assoc 1 (entget bEnt))))

 ) 
)

Or perhaps changing its value to something else:

 

(while
 (not
   (eq "SEQEND"
     (cdr
       (assoc 0
         (entget
           (setq bEnt
             (entnext bEnt)
           )
         )
       )
     )
   )
 )
 
 (if (eq "TAG" (cdr (assoc 2 (entget bEnt))))
   (entupd
     (cdr
       (assoc -1
         (entmod
           (subst
             (cons 1 "Lee Mac") (assoc 1 (entget bEnt)) (entget bEnt)
           )
         )
       )
     )
   )
 )
)

Now for the Visual LISP way:

 

Now that we want to operate on the block through Visual LISP, we need a Visual LISP Object to work with:

 

(setq bObj (vlax-ename->vla-object bEnt))

We could also test to make sure that the block has attributes using:

 

(eq :vlax-true (vla-get-HasAttributes bObj))

Now, iterating through the attributes is slightly easier in VL:

 

(foreach att (vlax-invoke bObj 'GetAttributes)

 ...

)

Or to include Constant Attributes also:

 

(foreach att (append (vlax-invoke bObj 'GetAttributes)
                    (vlax-invoke bObj 'GetConstantAttributes))

 ...

)

Now that we have bound each attribute object to the symbol 'att' we can operate on these objects within the foreach loop; for example to retrieve the value of an attribute with tag string "TAG":

 

(foreach att (append (vlax-invoke bObj 'GetAttributes)
                    (vlax-invoke bObj 'GetConstantAttributes))

 (if (eq "TAG" (vla-get-TagString att))
   (setq attVal (vla-get-TextString att))
 )
)

Notice that we use vlax-invoke in this case, as opposed to vlax-invoke-method or rather just vla-getAttributes. This is because the return of vlax-invoke is a list, which is much easier to deal with using standard Vanilla AutoLISP functions.

 

If we were to use vlax-invoke-method, or vla-getAttributes we would need to convert the variant that is returned into a list that we can manipulate:

 

(foreach att
 (vlax-safearray->list
   (vlax-variant-value
     (vla-getAttributes bObj)
   )
 )

 (if (eq "TAG" (vla-get-TagString att))
   (setq attVal (vla-get-TextString att))
 )
)

 

This should get you going, if you get stuck, just ask.

 

Lee

  • Thanks 1
Posted

Thanks for taking the time to explain the steps Lee, I'll look at it carefully and if I have any questions I'll be sure to ask. :)

  • 6 months later...
Posted

I've been Googling this for several days, and this is by far the best response I've seen. I was able to take the provided Visual Lisp code and immediately get the exact information I wanted out of the drawing. It was clear, brief and the explanations for each code snipped was extremely helpful.

 

Thank you so much!

Posted
I've been Googling this for several days, and this is by far the best response I've seen. I was able to take the provided Visual Lisp code and immediately get the exact information I wanted out of the drawing. It was clear, brief and the explanations for each code snipped was extremely helpful.

 

Thank you so much!

 

You're very welcome - I'm glad it could benefit you :)

 

Some related goodies can be found here :)

 

Enjoy!

 

Lee

Posted

FYI, vla-get-HasAttributes will error if applied to an object that isn't a block.

Posted
FYI, vla-get-HasAttributes will error if applied to an object that isn't a block.

 

To what code are you referring?

Posted
To what code are you referring?

Your above example. For AL, you perform all the necessary checks, but in VL, you forgot to check if the vla-object is a block before seeing if it has attributes.

Posted
Your above example. For AL, you perform all the necessary checks, but in VL, you forgot to check if the vla-object is a block before seeing if it has attributes.

 

I see how that might be misleading - the VL method is meant to use the variable from the AL selection, and I say 'we could also use' vla-get-HasAttributes - i.e. suggesting it as an alternative method to check for attributes. Perhaps I need to reword it.

Posted
I see how that might be misleading - the VL method is meant to use the variable from the AL selection, and I say 'we could also use' vla-get-HasAttributes - i.e. suggesting it as an alternative method to check for attributes. Perhaps I need to reword it.

Whatever floats your boat. :)

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