Cylis0509 Posted May 4, 2017 Posted May 4, 2017 Hi all, I found these lisps online and could use some help "merging" them. What I am trying to do is update the DEFAULT value in an attribute. I have many blocks with different names but they all have the same attribute tag. I need to update the tags default value. The first code works great but as you can see i have to specify the block name. I am trying to modify the second code which allows me to select multiple blocks but changes the attribute value. How can i modify the second code to change the Default Value not the main value. Thanks! (Defun c:test1 (/) (setq BlkName "MCNJ-UTIL-WATR-2100") (setq TagName "DTL_DATE") (setq BlkCol (vla-get-Blocks (vla-get-ActiveDocument (vlax-get-Acad-Object)))) (setq BlkDef (vla-Item BlkCol BlkName)) (vlax-for Obj BlkDef (if (and (= (vla-get-ObjectName Obj) "AcDbAttributeDefinition") (= (vla-get-TagString Obj) TagName) ) (progn (setq en_txt "05/01/17") (vla-put-textstring Obj en_txt) ) ) ) (princ) ) (defun C:test (/ BlkCol tx a e ) (setq a nil) (if (and (ssget ":L" '((0 . "INSERT"))) (while (not a) (setq e (car (nentselp "\nSelect attribute to replace: "))) (cond ((null e)(princ "\nTry again.")) ((= (cdr (assoc 0 (entget e)))) (setq a (cdr (assoc 1 (entget e))))) (t nil) ) ) (setq tx (getstring t "Enter new attribute value :")) ) (vlax-map-collection (setq BlkCol (vla-get-activeselectionset (vla-get-activedocument (vlax-get-acad-object)))) (function (lambda (b) (foreach at (vlax-invoke b 'getattributes) (if (eq (vla-get-textstring at) a) (vla-put-textstring at tx) ) ) ) ) ) ) (vla-delete BlkCol)(princ) ) Quote
Lee Mac Posted May 4, 2017 Posted May 4, 2017 Try the following, modify the variable values to suit: (defun c:defatt ( / def tag ) (setq tag [highlight]"TAG1"[/highlight] def [highlight]"My Default"[/highlight] ) (vlax-for blk (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object))) (if (= :vlax-false (vla-get-islayout blk) (vla-get-isxref blk)) (vlax-for obj blk (if (and (= "AcDbAttributeDefinition" (vla-get-objectname obj)) (= (strcase tag) (strcase (vla-get-tagstring obj))) (vlax-write-enabled-p obj) ) (vla-put-textstring obj def) ) ) ) ) (princ) ) (vl-load-com) (princ) Quote
Grrr Posted May 4, 2017 Posted May 4, 2017 Heres vanilla attempt - just for fun: ; (defatt '(("Tag1" "Defval1")("Tag2" "Defval2")("Tag3" "Defval3"))) (defun defatt ( L / d n e enx v ) (while (setq d (tblnext "BLOCK" (not d))) (and (setq n (cdr (assoc 2 d))) (not (wcmatch n "`*U*,`*T*")) (not (cdr (assoc 1 d))) (setq e (tblobjname "BLOCK" n)) (while (and (setq e (entnext e)) (/= "ENDBLK" (cdr (assoc 0 (setq enx (entget e)))))) (and (member '(0 . "ATTDEF") enx) (setq v (cadr (assoc (cdr (assoc 2 enx)) L))) (entmod (subst (cons 1 v) (assoc 1 enx) enx)) ); and ); while ); and ); while ); defun defatt Any remarks are appreciated (I'm not fully confident doing such stuff with vanilla). Quote
Cylis0509 Posted May 5, 2017 Author Posted May 5, 2017 Lee, As usual you never fail to impress or deliver! Thank you so much, this works perfect to get the job done. Made two small changes to make it more global, when I have a little more time I will play with adding the ability to select only the blocks you want and to select the attribute instead of typing it in. But for now it's perfect. You saved me from having to manually update 350+ blocks. ;; Lee-Mac - 2017 (defun c:defatt ( / def tag ) (setq tag (getstring t "Enter name of attribute to replace default value for: ")) (setq def (getstring t "Enter new default attribute value: ")) (vlax-for blk (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object))) (if (= :vlax-false (vla-get-islayout blk) (vla-get-isxref blk)) (vlax-for obj blk (if (and (= "AcDbAttributeDefinition" (vla-get-objectname obj)) (= (strcase tag) (strcase (vla-get-tagstring obj))) (vlax-write-enabled-p obj) ) (vla-put-textstring obj def) ) ) ) ) (princ) ) (vl-load-com) (princ) Quote
Cylis0509 Posted May 5, 2017 Author Posted May 5, 2017 Grrr, Thank you so much for you suggestion as well. It is really appreciated. Quote
Lee Mac Posted May 5, 2017 Posted May 5, 2017 As usual you never fail to impress or deliver! Thank you so much, this works perfect to get the job done. But for now it's perfect. You saved me from having to manually update 350+ blocks. Excellent - I'm glad the code proved useful! Made two small changes to make it more global, when I have a little more time I will play with adding the ability to select only the blocks you want and to select the attribute instead of typing it in. The following minor modifications will allow you to enter case-insensitive wildcard patterns for the block name & attribute tag (and you can separate multiple patterns with commas): ;; Lee-Mac - 2017 (defun c:defatt ( / bln def tag ) (if (= "" (setq bln (strcase (getstring t "\nSpecify block name filter (Use * for all) <*>: ")))) (setq bln "*") ) (if (= "" (setq tag (strcase (getstring "\nSpecify tag name filter (Use * for all) <*>: ")))) (setq tag "*") ) (setq def (getstring t "\nSpecify new default value: ")) (vlax-for blk (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object))) (if (and (= :vlax-false (vla-get-islayout blk) (vla-get-isxref blk)) (wcmatch (strcase (vla-get-name blk)) bln)) (vlax-for obj blk (if (and (= "AcDbAttributeDefinition" (vla-get-objectname obj)) (wcmatch (strcase (vla-get-tagstring obj)) tag) (vlax-write-enabled-p obj) ) (vla-put-textstring obj def) ) ) ) ) (princ) ) (vl-load-com) (princ) Quote
Cylis0509 Posted May 5, 2017 Author Posted May 5, 2017 Lee, Brilliant! Thank you. Hope I'm not being too greedy, but what if you wanted to do as ssget on the blocks and attribute so the user can select with pick box or window. I am still learning selection sets. In fact I'm trying to figure something out with them on another lisp. I will post in a separate thread if need be. I'm trying to figure out how to do a selection set that includes MTEXT,MULTILEADER,DIMENSION and on MTEXT,MULTILEADER do one thing and on DIMENSION do another... (and (setq ss_mm (ssget (list (cons 0 "MTEXT,MULTILEADER")))) (setq ss_dm (ssget '((0 . "DIMENSION")))) ) (repeat (setq x_mm (sslength ss_mm)) ... program .... ... program ... (repeat (setq x_dm (sslength ss_dm)) ... program ... This currently makes me window twice but works. Quote
Lee Mac Posted May 5, 2017 Posted May 5, 2017 what if you wanted to do as ssget on the blocks and attribute so the user can select with pick box or window. There are a couple of issues with this form of selection: An ssget selection only permits selection of primary objects in the drawing, and therefore selection of attribute references would need to be performed using multiple single pick selections. Since the program in this thread is operating on block definitions, a window selection of block references is not intuitive for the user, as the program would only need to process one block definition for each distinct reference in the selection, and all subsequent references inserted would be affected. Quote
Cylis0509 Posted May 5, 2017 Author Posted May 5, 2017 I think I understand what your saying, and if I do I may have explained myself wrong... (which I do a lot) I have a drawing with 350+ blocks, all with a different name and definition, but they all have the same 4 attributes in them. (It's a block library and we are using attributes to store information for the user.) Sometimes one attribute needs to be updated in ALL the blocks and sometimes in just a few. Like a mod date for example. Sometime we modify all them sometimes a handful. If this is the case does what you say still hold true? I hope i made more sense this time. Quote
Lee Mac Posted May 5, 2017 Posted May 5, 2017 I have a drawing with 350+ blocks, all with a different name and definition, but they all have the same 4 attributes in them. Sometimes one attribute needs to be updated in ALL the blocks and sometimes in just a few. I understand your situation, but in the general case a block definition is unlikely to only have a single reference, and therefore given that this program is operating on the block definition (as we are modifying the default attribute value held by the attribute definition, not the value held by the attribute reference), selection of multiple references of the same block has no meaning. Quote
Grrr Posted May 5, 2017 Posted May 5, 2017 I understand your situation, but in the general case a block definition is unlikely to only have a single reference, and therefore given that this program is operating on the block definition (as we are modifying the default attribute value held by the attribute definition, not the value held by the attribute reference), selection of multiple references of the same block has no meaning. Lee, on the other hand sounds interesting to Iterate over the: - blocks collection --- blocks refs inside the layout block, and extract their attrefs --- attdefs inside the block defs (defun test ( / attribs attdefs ) (vlax-for blk (vla-get-Blocks (vla-get-ActiveDocument (vlax-get-acad-object))) (if (eq :vlax-false (vla-get-IsXref blk)) (cond ( (eq :vlax-true (vla-get-IsLayout blk)) (vlax-for o blk (and (eq "AcDbBlockReference" (vla-get-ObjectName o)) (eq :vlax-true (vla-get-HasAttributes o)) (setq attribs (cons (vlax-invoke o 'GetAttributes) attribs)) ); and ); vlax-for o ) (T (vlax-for o blk (and (eq "AcDbAttributeDefinition" (vla-get-ObjectName o)) (setq attdefs (cons o attdefs)) ); and ); vlax-for o ); T ); cond ); if ); vlax-for blk (list (cons "attr" attribs) (cons "attd" attdefs) ) ); defun and then do some wire-ups between the attdef and its attrib references - once we obtained both lists - for instance check for the same TagString and put the TextString from the attdef to the attref. Quote
JSCraigen Posted January 13, 2023 Posted January 13, 2023 On 5/4/2017 at 5:18 PM, Lee Mac said: Try the following, modify the variable values to suit: (defun c:defatt ( / def tag ) (setq tag [highlight]"TAG1"[/highlight] def [highlight]"My Default"[/highlight] ) (vlax-for blk (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object))) (if (= :vlax-false (vla-get-islayout blk) (vla-get-isxref blk)) (vlax-for obj blk (if (and (= "AcDbAttributeDefinition" (vla-get-objectname obj)) (= (strcase tag) (strcase (vla-get-tagstring obj))) (vlax-write-enabled-p obj) ) (vla-put-textstring obj def) ) ) ) ) (princ) ) (vl-load-com) (princ) I have tried using this and other variations to specify default text in block attribute after insert. all of the information will be static so it could be set into the autolisp and would not need to change. it would need to be global, and would need to be regenerated afterward. it is possible that I am having an issue because the text I am wanting to insert has a " symbol in it. is there a way around that? see below. I would be grateful for any help. Bln (nmbs-d-title) Tag (DRAWING) Def (%<\AcVar ctab \f"%tc1">%) Quote
Lee Mac Posted January 13, 2023 Posted January 13, 2023 You'll need to escape those characters (including the backslashes), e.g.: (defun c:defatt ( / def tag ) (setq tag "TAG1" def "%<\\AcVar ctab \\f\"%tc1\">%" ) (vlax-for blk (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object))) (if (= :vlax-false (vla-get-islayout blk) (vla-get-isxref blk)) (vlax-for obj blk (if (and (= "AcDbAttributeDefinition" (vla-get-objectname obj)) (= (strcase tag) (strcase (vla-get-tagstring obj))) (vlax-write-enabled-p obj) ) (vla-put-textstring obj def) ) ) ) ) (princ) ) (vl-load-com) (princ) Quote
Vidiot12 Posted June 27, 2023 Posted June 27, 2023 I've been looking around and this topic is about as close as I can find to what I need. Lets see if I can explain coherently... I need to update a large block library and have come up with a new generic dynamic block. My hope is to insert several generics, attout to excel, fill in the attributes with info from the old library, attin the attributes that are not dynamic or generated via fields, and finally run a .lisp to update the generic blocks default attributes with what is current , then save with a new name generated by a couple of the attributes. (Hoping this could be used on individually selected blocks as well to save time creating new blocks in the future for drafters prior to wblocking. Not necessary though since reading above makes this seem like a heavy lift.) Attributes to update current to default are: ALIAS, MANUFACTURER, MODEL#, PART#, CAPEX, OPEX. New block name would be PREFIX_MANUFACTURER_MODEL#_PART# I am trying to learn lisp but all the vla/vlax is beyond me at this point. If anyone is willing to work on this I would love comments in the code to help me wrap my pee brain around it and not have to lean so hard on the hive. Quote
Vidiot12 Posted June 27, 2023 Posted June 27, 2023 Guessing I should add a file to help. MakeCurrentAttDefault.dwg 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.