Visual LISP, AutoLISP and General Customization
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

LISP to Select Blocks and Add Attributes

53 REPLIES 53
SOLVED
Reply
Message 1 of 54
Kyle.para
12913 Views, 53 Replies

LISP to Select Blocks and Add Attributes

Hi All,

 

We have to add a ton of attributes to all of our blocks.

 

I found code that was originally written by Lee Mac, but it was designed to type in the block name that you wanted.

 

I just want to be able to select all the blocks that I want and then have it insert the tags into all of the blocks that are selected.

 

I tried to change the "name enter box" to a select command but the program comes back with no blocks found.

 

Sorry I am new to this and may as well be trying to learn another language.

 

(defun c:addattribs ( / blk def )
  ; Get Entities
    (while (not blk)
            (princ "\nSelect Blocks to Update:")
               (setq blk (ssget '((-4 . "<NOT") (0 . "INSERT,POLYLINE,VIEWPORT") (-4 . "NOT>"))))
    ) ;_  end while
        )
        (if (/= "" blk)
        (progn
            (setq def (vla-item (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object))) blk))
            (vla-addattribute def
                (getvar 'textsize)
                acattributemodelockposition
                "New Attribute 1"
                (vlax-3D-point 0 0)
                "NEW_TAG1"
                "New Value 1"
            )
            (vla-addattribute def
                (getvar 'textsize)
                acattributemodelockposition
                "New Attribute 2"
                (vlax-3D-point 0 (- (* 1.5 (getvar 'textsize))))
                "NEW_TAG2"
                "New Value 2"
            )
            (command "_.attsync" "_N" blk)
        )
    )
    (princ)
)
(vl-load-com) (princ)

 

Thanks.

53 REPLIES 53
Message 2 of 54
Ranjit_Singh1
in reply to: Kyle.para


@Kyle.para wrote:

Hi All,

 

We have to add a ton of attributes to all of our blocks.

 

I found code that was originally written by Lee Mac, but it was designed to type in the block name that you wanted.

 

I just want to be able to select all the blocks that I want and then have it insert the tags into all of the blocks that are selected.

 


See post 4 of 4 here. Call the routine as (somefunc '("YourTAG1" "YourTAG2 "YourTAG3" .....) '("Value1" "Value2" "Value3" ......))

 

EDIT: Misunderstood the request. Ignore my reply 

Message 3 of 54
Ranjit_Singh1
in reply to: Kyle.para


@Kyle.para wrote:

Hi All,

 

.............

 

I just want to be able to select all the blocks that I want and then have it insert the tags into all of the blocks that are selected.

...................

 


When you say all the blocks, do you mean different block definitions or just all instances of one particular block? If you are talking different block definitions then how will the computer decide on the tag position for each of these blocks? You need to specify one particular block, specify the position of the new tag(s) and then move to a different block. The below code will allow you to pick a block and then add the tag. All instances of that block should update.

 

(defun c:somefunc  (/ vlaObj testblk)
 (setq vlaObj(vlax-ename->vla-object
  (cdr
   (assoc 330 (entget (tblobjname "block" (setq testblk (cdr (assoc 2 (entget (car (entsel))))))))))))
 (while (setq pt1 (getpoint "\nEnter new Tag Position :")
              prm (getstring "\nEnter Tag Prompt :")
              tag (getstring "\nEnter Tag Name :")
              val (getstring "\nEnter Tag Value :"))
  (vla-addattribute vlaObj 20 acattributemodelockposition prm (vlax-3d-point pt1) tag val)
 (vl-cmdf "_.attsync" "_N" testblk))
 (princ))

 

Message 4 of 54
Kyle.para
in reply to: Ranjit_Singh1

Hi Ranjit,

 

Yes sorry I was hoping we could just force the program to loop over and over again for different block definitions.

I have multiple blocks with different names that all need the exact same attributes

 

If I can only do one at a time that is OK though, but what I am looking for is to have the lisp push specified attributes to the block automatically without any input from the user.

 

For example I would select block A and it would add the following tags automatically Description, Model, Comments etc...

 

Then I would move to the next one say block B and have it automatically generate the same tags for that block.

 

I need to blocks to be invisible as well.

 

Here's the original program that Lee Mac did, that actually runs to see what I mean.

 

(defun c:addattribs ( / blk def )
    (while
        (not
            (or (= "" (setq blk (getstring t "\nName of block to update: ")))
                (tblsearch "BLOCK" blk)
            )
        )
        (princ (strcat "\nBlock \"" blk "\" not found."))
    )
    (if (/= "" blk)
        (progn
            (setq def (vla-item (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object))) blk))
            (vla-addattribute def
                (getvar 'textsize)
                acattributemodelockposition
                "New Attribute 1"
                (vlax-3D-point 0 0)
                "NEW_TAG1"
                "New Value 1"
            )
            (vla-addattribute def
                (getvar 'textsize)
                acattributemodelockposition
                "New Attribute 2"
                (vlax-3D-point 0 (- (* 1.5 (getvar 'textsize))))
                "NEW_TAG2"
                "New Value 2"
            )
            (command "_.attsync" "_N" blk)
        )
    )
    (princ)
)
(vl-load-com) (princ)

 

This is exactly what I need, but I don't want to enter the name of specified block.  I just want to select a block but do the same thing.

 

Thanks,

Message 5 of 54
john.uhden
in reply to: Kyle.para

Try this variation (not tested)...

 

(defun c:addattribs ( / ss i blk blks def )
    (and
       (setq ss (ssget "X" '((0 . "INSERT"))))
       (setq i (sslength ss))
       (while (> i 0)
          (setq blk (cdr (assoc 2 (entget (ssname ss (setq i (1- i)))))))
          (if (not (vl-position blk blks))(setq blks (cons blk blks)))
       )
    )
    (foreach blk blks
         (setq def (vla-item (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object))) blk))
         (vla-addattribute def
             (getvar 'textsize)
             acattributemodelockposition
             "New Attribute 1"
             (vlax-3D-point 0 0)
             "NEW_TAG1"
             "New Value 1"
         )
         (vla-addattribute def
             (getvar 'textsize)
             acattributemodelockposition
             "New Attribute 2"
             (vlax-3D-point 0 (- (* 1.5 (getvar 'textsize))))
             "NEW_TAG2"
             "New Value 2"
         )
         (command "_.attsync" "_N" blk)
     )
    (princ)
)
(vl-load-com) (princ)

I'm not sure what happens with XRefs.  If you want to select the blocks instead of all of them, just remove "X"

John F. Uhden

Message 6 of 54
Ranjit_Singh1
in reply to: Kyle.para

Try my below code. As far as I know you have to specify the values at some point. if all your blocks will use the same tags then you still need to define it at least once. Call the below code with list of arguments. Make sure to pass same number of elements in each list.

You are required to pick a point and it will allow you only as many times to pick the point, as the number of elements in the list. If you do not specify a point in any block then it moves on to the next block and starts at TAG1. Call it like this (somefunc '("Prompt1" "Prompt2" "Prompt3") '("TAG1" "TAG2" "TAG3") '("VAL1" "VAL2" "VAL3")) If you wish to leave certain elements empty then do no pass those values but pass empty strings like (somefunc '("Prompt1" "Prompt2" "Prompt3") '("TAG1" "TAG2" "TAG3") '("" "VAL2" ""))

 

(defun somefunc  (lst1 lst2 lst3 / checklst entname i prm pt1 tag testblk val vlaobj)
 (and (= (length lst1) (length lst2) (length lst3))
      (mapcar '(lambda (x)
                (setq vlaobj (vlax-ename->vla-object
                              (setq entname (cdr (assoc 330 (entget (tblobjname "block" (setq testblk (cdr (assoc 2 (entget x)))))))))))
                (and (not (member entname checklst))
                     (setq checklst (cons entname checklst))
                     (z2fd x)
                     (setq i 0)
                     (while (and (< i (length lst1))
                                 (not (vl-catch-all-error-p (setq pt1 (vl-catch-all-apply 'getpoint '("\nEnter Tag Position :"))))))
                      (setq prm (nth i lst1)
                            tag (nth i lst2)
                            val (nth i lst3))
                      (vla-addattribute vlaobj 20 acattributemodelockposition prm (vlax-3d-point pt1) tag val)
                      (setq i (1+ i))
                      (command-s "._attsync" "_N" testblk))))
              (mapcar 'cadr (ssnamex (ssget "_x" '((0 . "INSERT")))))))
 (princ))


(defun z2fd  (x)
 (setvar 'ctab (cdr (assoc 410 (entget x))))
 (not (command-s "._zoom" "_O" x "")))
Message 7 of 54
Kyle.para
in reply to: john.uhden

Hi John,

 

This is very close. I just would like to select them though.

I removed x but it came up with an error message. "error too few arguments"

 

Also what's the command to make the tag invisible?

 

Thanks a lot!

Message 8 of 54
Kyle.para
in reply to: Ranjit_Singh1

Hi Ranjit,

 

This is a silly question, but I don't even know how to run this.

 

Thanks,

Message 9 of 54
Ranjit_Singh1
in reply to: Kyle.para

I thought I explained it, maybe not well enough. Load both the lisp functions through appload (somefunc and z2fd). At the command prompt type

(somefunc '("Prompt1" "Prompt2" "Prompt3") '("TAG1" "TAG2" "TAG3") '("VAL1" "VAL2" "VAL3")). Use whatever values you need in place of Prompt1, Tag1, Val1 etc.

I am using 3 values as an example but you can use only 2 or how many ever you need. Fo rexample if you have 2 tag values then call the routine by typing (somefunc '("Prompt1" "Prompt2") '("TAG1" "TAG2") '("VAL1" "VAL2")) at command prompt.

Message 10 of 54
Kyle.para
in reply to: Ranjit_Singh1

No you probably explained it OK it's just me who has no clue. Smiley Very Happy

 

Ok so I figured out how to get it to work and it works OK except when I click on a block and then click on the next box it's very glitchy.

 

Also the tags land in a very far off place under the blocks.

 

Thanks,

Message 11 of 54
Ranjit_Singh1
in reply to: Kyle.para

Check the text height value. I used a value of 20. You need to set it to whatever value you use in your drawing.

(vla-addattribute vlaobj 20 acattributemodelockposition prm (vlax-3d-point pt1) tag val); change the 20 to your text height and try
Message 12 of 54
john.uhden
in reply to: Kyle.para

When I said to delete "X" I meant to change

 

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

to
(setq ss (ssget '((0 . "INSERT"))))

I'm not sure what you mean about tag visibility.  I haven't run the routine, but maybe it leaves you looking at the block contents, so the ATTDEF is exposed.

But if you want the attibutes not to appear, you can either freeze their layer, or change their visibility code (vlax-put object 'visible 0), or maybe there's something specific about invisible attributes that I don't remember (but you can find it in help). 

John F. Uhden

Message 13 of 54
Kyle.para
in reply to: Kyle.para

Thanks John I will try it Monday. I was only removing the X

What I meant by the visibility was in the attdef there is an option to tick attributes to invisible when they're inside of block. So that you only see the attributes in the block editor. I don't want the text to show up when they're in the model. I just want them hidden in the block.

Thanks again for your help!
Message 14 of 54
Ranjit_Singh1
in reply to: Kyle.para

You need to change the mode argument of acAttributeModeLockPosition to acAttributeModeInvisible.

Message 15 of 54
john.uhden
in reply to: Kyle.para

From the AutoCAD 2002 help:

 

"Mode
Sets options for attribute values associated with a block when you insert the block in a drawing.

The default values are stored in theAFLAGS system variable. Changing the AFLAGS setting affects the default mode for new attribute definitions and does not affect existing attribute definitions.

Invisible

Specifies that attribute values are not displayed or printed when you insert the block.  ATTDISP overrides Invisible mode."

 

I don't know if that applies to the visibility of inserted attributes, but my former suggestions are valid.

I suppose we could make you an ATTVIS.lsp to turn on/off all attributes or just those in selected block insertions.

John F. Uhden

Message 16 of 54
Kyle.para
in reply to: john.uhden

@john.uhden

 

The program works now by selecting the blocks, I got it to work by removing the "X" as you suggested.

The only thing that will make this perfect is forcing CAD to build the Attributes invisibly in the blocks.

 

Here's a screenshot of the ATTDEF screen showing the option to check.

 

attdef.jpg

 

Thanks,

Message 17 of 54
john.uhden
in reply to: Kyle.para

I wasn't aware that an ATTDEF has an "Invisible" property.  This is not true for ATTRIBs.

It is not to be confused with the "Visible" property, which I think all graphic objects have.

 

Whatever code you use for creating the ATTDEFs, add the line (vlax-put attdef 'Invisible -1).

 

Note that "attdef" is what I named the vla-object here for example only.  The actual symbol name in your code is probably different and must be used instead.

John F. Uhden

Message 18 of 54
Kyle.para
in reply to: john.uhden

Man I am sorry but I have no clue what the name of the symbol is in this code.  I tried to add that line but I'm not getting anywhere.

 

 

(defun c:addattribs ( / ss i blk blks def )
    (and
       (setq ss (ssget "X" '((0 . "INSERT"))))
       (setq i (sslength ss))
       (while (> i 0)
          (setq blk (cdr (assoc 2 (entget (ssname ss (setq i (1- i)))))))
          (if (not (vl-position blk blks))(setq blks (cons blk blks)))
       )
    )
    (foreach blk blks
         (setq def (vla-item (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object))) blk))
         (vla-addattribute def
             (getvar 'textsize)
(vlax-put ? 'Invisible -1) acattributemodelockposition "New Attribute 1" (vlax-3D-point 0 0) "NEW_TAG1" "New Value 1" ) (vla-addattribute def (getvar 'textsize)
(vlax-put ? 'Invisible -1) acattributemodelockposition "New Attribute 2" (vlax-3D-point 0 (- (* 1.5 (getvar 'textsize)))) "NEW_TAG2" "New Value 2" ) (command "_.attsync" "_N" blk) ) (princ) ) (vl-load-com) (princ)

 

Message 19 of 54
john.uhden
in reply to: Kyle.para

I just found out that the vla-addattribute method can take a Mode code, so you could use the following...

 

         (vla-addattribute def
             (getvar 'textsize)
             (vlax-put ? 'Invisible -1)
             acattributemodelockposition
acAttributeModeInvisible
"New Attribute 1"
(vlax-3D-point 0 0)
"NEW_TAG1"
"New Value 1"
)
 
 

Do this for as many attributes as you are creating.  I think your example creates two.

 

Bear in mind:

"The Mode values are as follows:

acAttributeModeInvisible

Specifies that attribute values won't appear when you insert the block. The ATTDISP system variable overrides the Invisible mode.

..."

Also, get rid of that "X" again if you want to select the blocks

John F. Uhden

Message 20 of 54
Kyle.para
in reply to: john.uhden

Thanks @Ranjit_Singh1 & @john.uhden

 

Ranjit had mentioned the acattributemodeinvisibile before and I tried to change it yesterday but it didn't work the way I was doing it.

 

I was hoping one of you could tell me one last thing.  How do  I change the height of the text?

 

Thanks,

 

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Forma Design Contest


AutoCAD Beta