CADalyst Posted February 18, 2011 Posted February 18, 2011 I am new to this forum and LISP programming so please bear with my lack of knowledge. I have a couple of hundred blocks which I'm interested in changing the values of specific tags using lisp (or something else). I have lots of different blocks, and they all have two attributes. The tag for attribute 1 is "X", with a value of "100" The tag for attribute 2 is "Y", with a value of "200" Is is possible to change all the blocks in the drawing, such that the attribute 1 value is renamed from "100" to "1", and the attribute 2 value is renamed from "200" to "2". I would like, if possible, to preserve and leave unchanged the tags associated with the respective attributes, and change only the value. So basically, once the script is done, I will still have the blocks with the same attributes, just different tag values. To clarify; I'm interested in replacing attribute values rather than changing attribute tag names. I hope this makes sense and that it is possible. Many Thanks Quote
Tharwat Posted February 18, 2011 Posted February 18, 2011 Check this out , and you should select the tag in the Attributed Block ... (defun c:Test (/ newTag ss e) ; Tharwat 18. Feb, 2011 (if (and (setq newTag (getstring "\n New string :")) (setq ss (car (nentsel "\n Select tag in Attribute Block :"))) (eq "ATTRIB" (cdr (assoc 0 (entget ss)))) ) (progn (setq e (entget ss)) (entupd (cdr (assoc -1 (entmod (subst (cons 1 newTag) (assoc 1 e) e))))) ) (princ "\n Please select Attributed Block Only ") ) (princ) ) Tharwat Quote
Lt Dan's legs Posted February 18, 2011 Posted February 18, 2011 (edited) (defun c:test ( / ss_id revise_at *error* l ) (vl-load-com) ;|¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-; ;- Revise attributes ; ;- ename = entity name ; ;- _list = A list of attribute tags and changes (list (tag . new value)) ; ;-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-; ; Example: ; ; (revise_at (car (entsel)) (list (cons "x" "1")(cons "y" "2"))) ; ; Returns: ; ; nil ; ;-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤|; (defun revise_at ( ename _list ) (foreach x _list (foreach l (vlax-invoke (vlax-ename->vla-object ename) 'GetAttributes ) (if (eq (strcase (vla-get-TagString l) ) (strcase (car x) ) ) (vla-put-TextString l (cdr x) ) ) ) ) ) ;|¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-; ;- Turns a selection set into a list of entity names ; ;- ss = selection set ; ;-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-; ; Example: ; ; (ss_id (ssget)) ; ; Returns: ; ; (<Entity name: 7c3b3910> <Entity name: 7c3b3918>) ; ;-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤|; (defun ss_id ( ss / id _list ) (if (eq 'PICKSET (type ss) ) (repeat (setq id (sslength ss) ) (setq _list (append _list (list (ssname ss (setq id (1- id) ) ) ) ) ) ) ) _list ) ;|¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤-¤|; (defun *error* ( msg ) (setvar' nomutt 0) (princ) ) (princ "\nSpecify blocks to modify: ") (setvar' nomutt 1) (if (setq l (ss_id (ssget (list (cons 0 "insert") ) ) ) ) (foreach x l (revise_at x (list (cons "X" "100") (cons "Y" "200") ) ) ) (princ "\nNothing selected!") ) (setvar' nomutt 0) (princ) ) Edited February 18, 2011 by Lt Dan's legs Quote
BlackBox Posted February 18, 2011 Posted February 18, 2011 Just for fun... (defun c:FOO (/ acadDoc ss blkDef textString) (vl-load-com) (vla-startundomark (setq acadDoc (vla-get-activedocument (vlax-get-acad-object)))) (if (setq ss (ssget "_x" '((0 . "INSERT")))) (progn (vlax-for x (setq ss (vla-get-activeselectionset acadDoc)) (if (= :vlax-true (vla-get-hasattributes x)) (progn (setq blkDef (vla-item (cond (blockTable) ((setq blockTable (vla-get-blocks acadDoc)))) (vla-get-name x))) (foreach att (vlax-invoke x 'getattributes) (vlax-for item blkDef (if (and (= "AcDbAttributeDefinition" (vla-get-objectname item)) (= (vla-get-tagstring att) (vla-get-tagstring item)) (cond ((= "100" (setq textString (vla-get-textstring att))) (setq textString "1")) ((= "200" textString) (setq textString "2")) [color=blue];; <- Add more options here [/color] )) (vla-put-textstring att textString))))))) (vla-delete ss))) (vla-endundomark acadDoc) (princ)) Quote
Tharwat Posted February 18, 2011 Posted February 18, 2011 Nice routine Renderman. How about adding more filters to catch the (wanted) one. (setq ss (ssget "_x" '((0 . "INSERT")[color=white](66 . 1)[/color]))) Quote
BlackBox Posted February 18, 2011 Posted February 18, 2011 Nice routine Renderman. Thanks. How about adding more filters to catch the (wanted) one. (setq ss (ssget "_x" '((0 . "INSERT")[color=white](66 . 1)[/color]))) Same difference - I don't use DXF codes for very much, I forgot all about (66 . 1) Quote
Lee Mac Posted February 18, 2011 Posted February 18, 2011 Another approach: (defun c:test ( / ss ) (vl-load-com) (if (ssget "_:L" '((0 . "INSERT") (66 . 1))) (progn (vlax-for block (setq ss (vla-get-ActiveSelectionSet (vla-get-ActiveDocument (vlax-get-acad-object)) ) ) (mapcar (function (lambda ( attrib ) (if (member (vla-get-TagString attrib) '("X" "Y")) (vla-put-TextString attrib (chr (ascii (vla-get-TextString attrib)))) ) ) ) (vlax-invoke block 'GetAttributes) ) ) (vla-delete ss) ) ) (princ) ) Renderman, Not picking on you, but I noticed a few things: (if (setq ss (ssget "_x" '((0 . "INSERT")))) (progn (vlax-for x (setq ss (vla-get-activeselectionset acadDoc)) No need for the first 'setq' expression. (setq blkDef (vla-item (cond (blockTable) ((setq blockTable (vla-get-blocks acadDoc)))) (vla-get-name x))) (foreach att (vlax-invoke x 'getattributes) (vlax-for item blkDef (if (and (= "AcDbAttributeDefinition" (vla-get-objectname item)) (= (vla-get-tagstring att) (vla-get-tagstring item)) (cond ((= "100" (setq textString (vla-get-textstring att))) (setq textString "1")) ((= "200" textString) (setq textString "2")) [color=blue];; <- Add more options here [/color] )) (vla-put-textstring att textString))))))) Why do you dig through the Block Definition? Quote
alanjt Posted February 19, 2011 Posted February 19, 2011 You could also step through the attributes with foreach (doesn't require anonymous function to be defined)... (foreach attrib (vlax-invoke block 'GetAttributes) (if (vl-position (vla-get-TagString attrib) '("X" "Y")) (vla-put-TextString attrib (chr (ascii (vla-get-TextString attrib)))) ) ) I don't see the reason to use mapcar+lambda unless you have more than one list to simultaneously step through or you want a list of each item's end result. Not sure what's quicker, but you could also use (substr (vla-get-TextString attrib) 1 2) (might not have my numbers 100%; I don't have AutoCAD to check). Quote
resullins Posted April 11, 2011 Posted April 11, 2011 I'm going to ressurect this thread in hopes someone's bored.... I have sort of the same issue as above, and while I'm learning LISP, I'm not really to the point of being able to handle blocks. I have one block that has 2 attributes that need to be changed. One of the attributes will always be one of two things, a small "C" for cable-mounted, or a small "P" for panel-mounted. The other attribute will need to be a variety of things, so it will be manual entry. I'm assuming it's going to be easiest to make these two different commands? Would any of the above items get me close? Quote
JohnM Posted April 11, 2011 Posted April 11, 2011 if you have express tools loaded just use the gatte command Quote
resullins Posted April 11, 2011 Posted April 11, 2011 (edited) Wow... I never knew that was there. I've definitely never used that command. Now, here's a dumb question, is there a code located somewhere for that command? I'd really like to alter it so it works a little better. I.e., the block we're trying to modify is set up so that it's REALLY hard to select the block without selecting an attribute with the first prompt. But that 2 attributes that are really prominent aren't the ones that I'm trying to modify, so it's a little difficult to use for my purposes. Maybe I'm just going to have to get better at LISP and write my own code. Edited April 11, 2011 by resullins Misleading typo... It's a Monday. Quote
JohnM Posted April 11, 2011 Posted April 11, 2011 for a simple change the gatte works fine and if you want to chang the code its in the express folder (not sure about newer versions) you can change it for personel use but not for sharing. i would copy it before making any changes. but there are a ton of good block lisp here and there is no better way to learn lisp than to start writting your own Quote
BlackBox Posted April 12, 2011 Posted April 12, 2011 I.e., the block we're trying to modify is set up so that it's REALLY hard to select the block without selecting an attribute with the first prompt. But that 2 attributes that are really prominent aren't the ones that I'm trying to modify, so it's a little difficult to use for my purposes. Maybe I'm just going to have to get better at LISP and write my own code. I'm curious to know how you "set up [a block] so that it's really hard to select... without selecting an attribute with the first prompt"...? Why can't you simply step through a selection set of attributed blocks using DXF code (66 . 1) in your SSGET filter, then using VLAX-FOR on the ActiveSelectionSet Property of the ActiveDocument Object? Quote
resullins Posted April 12, 2011 Posted April 12, 2011 Why can't you simply step through a selection set of attributed blocks using DXF code (66 . 1) in your SSGET filter, then using VLAX-FOR on the ActiveSelectionSet Property of the ActiveDocument Object? First, you may as well be speaking Greek to me. I very recently found out how naive I am about this program... so forgive me, I'm trying to learn, but that made NO sense to me. The block is three pieces of text with a small ellipse and a line running around them. And we often need to select forty or fifty at a time. Quote
BlackBox Posted April 12, 2011 Posted April 12, 2011 First, you may as well be speaking Greek to me. I very recently found out how naive I am about this program... so forgive me, I'm trying to learn, but that made NO sense to me. The block is three pieces of text with a small ellipse and a line running around them. And we often need to select forty or fifty at a time. No worries, we all start somewhere... I am by no means an expert myself. That said, become familiar with the Developer Documentation (hit F1 in the VLIDE) Without going into too much detail, as I understand this is 'Greek' to you, here is an example of what I posted previously: :: Make a selection set of attributed blocks :: [Make] a selection set of attributed blocks using DXF code (66 . 1) in your SSGET filter (setq ss (ssget "_x" [color=teal]; The "_x" selects all objects that match the following filter[/color] (list '(0 . "INSERT") [color=teal]; This indicates blocks[/color] '(2 . "[color=red]BlockName[/color]") [color=teal]; This is the non-dynamic block's name[/color] '(66 . 1) [color=teal]; This indicated an attributed block[/color] (cons 410 (getvar 'ctab))))) [color=teal]; This specifies the current tab[/color] :: Step through the selection set :: simply step through [the] selection set of attributed blocks ... using VLAX-FOR on the ActiveSelectionSet Property of the ActiveDocument Object (vl-load-com) [color=teal]; This loads the visual lisp extensions to autolisp[/color] [color=blue];; If there is a valid selection set:[/color] (if (setq ss (ssget "_x" (list '(0 . "INSERT") '(2 . "[color=red]BlockName[/color]") '(66 . 1) (cons 410 (getvar 'ctab))))) [color=blue];; Then do this:[/color] (progn [color=teal];; Foreach block in the active selection set[/color] (vlax-for block (setq ss (vla-get-activeselectionset (vla-get-activedocument (vlax-get-acad-object)))) [color=blue];; <- Add code to search through block attributes here[/color] ) [color=teal];; Delete the selection set from memory[/color] (vla-delete ss)) [color=teal][color=blue];; Else do this:[/color] ;; Inform the user nothing selected [/color] (prompt "\n** Nothing selected ** ")) Again, as this may read to you as 'Greek' simply try to absorb the 'anatomy' of the function's tasks, and it will make (more?) sense later when you become more familiar. Hope this helps! Quote
BlackBox Posted April 13, 2011 Posted April 13, 2011 why (setq ss at all? For the filter' date=' of course... ss = nil. The purpose of the [b']GATTE[/b] command is to "Globally change attribute values for all insertions of a specific block". (^^ Hence the ssget call ^^) With a valid selection set, one can quickly step through, and evaluate the block's attributes only making changes to the values as needed. The (one?) alternative would be to step through the entire block collection, and conditionally identify the desired block, then evaluate the attributes. Skipping blocks that are not desired. That seems very inefficient to me (not that the above example is perfect by any means!). Quote
Lt Dan's legs Posted April 13, 2011 Posted April 13, 2011 forgive me for not being clear I understand the use of ssget Why (Setq ss in the first place? you setq ss here (setq ss (vla-get-activeselectionset (vla-get-activedocument (vlax-get-acad-object)))) only to (vla-delete ss)) Quote
BlackBox Posted April 13, 2011 Posted April 13, 2011 (edited) forgive me for not being clear I understand the use of ssget Why (Setq ss in the first place? you setq ss here (setq ss (vla-get-activeselectionset (vla-get-activedocument (vlax-get-acad-object)))) only to (vla-delete ss)) This (multi page) thread may help explain: VLAX-FOR: Xref Table? Edited April 13, 2011 by BlackBox Quote
Recommended Posts
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.