TheSwamp

Code Red => AutoLISP (Vanilla / Visual) => Topic started by: TimSpangler on February 23, 2005, 12:08:12 PM

Title: Global Attribute Update?
Post by: TimSpangler on February 23, 2005, 12:08:12 PM
I use model space to create all of geometry then I use the Layout Tabs and create viewports in paperspace. In paperspace I insert my titleblock as a block w attributes.  If I have a 15 sheet drawing and the phone number changes or the project name changes I must go to every sheet and update the attributes.  I am triing to creat a routine that will automatically update all of the layout tabs for me.  I have created a routine to get the information from the corrected sheet but I can't for the life of me figure out how to get that info to update in the other tabs.  THe routine that generates the info send it out in an assoc list like such:

((PROJECTNAME . My Project)(PROJECTNUMBER . TGS001))

I have about eight of them total in the list)

Could someone lead me in the right direction as to how to go about this?

(Maybe I just need to eat?  Yeah me  thinks so.  I'll be right back.  BK here I come)
Title: Global Attribute Update?
Post by: daron on February 23, 2005, 12:30:02 PM
Tim, I think if you define your parameters through activex, you should be able to vla-put-textstring to a vla-get-tagname or however you intend to autochange them, run them through a mapcar or foreach procedure and that should take care of it. Too bad you can't just put the block in Mspace and viewport to each in each layout?!?
Title: Global Attribute Update?
Post by: DanB on February 23, 2005, 12:32:58 PM
Have you tried the Global Attribute Editor command "gatte?" Not sure if this is an express tool function or not...
Title: Global Attribute Update?
Post by: ELOQUINTET on February 23, 2005, 12:35:47 PM
am i missing something, you can't do this with express tools gatte command?
Title: Global Attribute Update?
Post by: ELOQUINTET on February 23, 2005, 12:37:33 PM
the only pitfall of this is that all of the layouts have to be in one drawing file but it does what you want i believe.
Title: Global Attribute Update?
Post by: TimSpangler on February 23, 2005, 12:47:28 PM
Yes Gatte works fine for one at a time, I have 8-10 that I would like to do at once.  I'll look into the activeX aproach and see if I can go from there.

Thanks Everyone
Title: Global Attribute Update?
Post by: ELOQUINTET on February 23, 2005, 12:53:16 PM
i don't follow tim it does multiple. after you input the new text it asks if you want to change all layouts and bingo it changes them all. maybe i'm misinterpreting your intentions  :?
Title: Re: Global Attribute Update?
Post by: CADaver on February 23, 2005, 01:00:39 PM
Try HERE (http://www.theswamp.org/phpBB2/viewtopic.php?t=1100&postdays=0&postorder=asc&highlight=changeatt&start=0)  Look for ChangeAtt lisp code.
Title: Global Attribute Update?
Post by: ELOQUINTET on February 23, 2005, 01:15:49 PM
ok cadaver i loaded that lisp and it does nothing for me. what is supposed to happen after user enters initials?
Title: Global Attribute Update?
Post by: ELOQUINTET on February 23, 2005, 01:21:05 PM
cadaver i'm no expert but is that just for creating a plotstamp? if so, what's wrong with this method it works great for me? again maybe i'm way off dunno?

http://afralisp.com/lisp/rtext.htm
Title: Global Attribute Update?
Post by: CADaver on February 23, 2005, 03:22:11 PM
Quote from: ELOQUINTET
ok cadaver i loaded that lisp and it does nothing for me. what is supposed to happen after user enters initials?
You got my Stamp lisp instead of ChangeAtt.

Here:


Code: [Select]
(defun changeAtt (ent tag val / entl ins)
  (setq ins ent)
  (while (and ent
           (/= "SEQEND" (cdr (assoc 0 (setq entl (entget ent))))))
    (if (and (= (cdr (assoc 0 entl)) "ATTRIB")
             (= (cdr (assoc 2 entl)) tag))
      (entmod (subst (cons 1 val) (assoc 1 entl) entl)))
    (setq ent (entnext ent)))
  (entupd ins)
)


Now you just need to pass it the desired data in the form of

Code: [Select]
(changeatt ent <attribute tag> <newvalue>)
Title: Global Attribute Update?
Post by: CADaver on February 23, 2005, 03:37:21 PM
Quote from: ELOQUINTET
cadaver i'm no expert but is that just for creating a plotstamp? if so, what's wrong with this method it works great for me? again maybe i'm way off dunno?

http://afralisp.com/lisp/rtext.htm
A couple of reasons.  
One not everyone has express tools RTEXT and some of those people are our clients.  

Another is legacy, RTEXT is an express tool that may or may not be supported in the next release.  I am loathe to build a procedure on something that may vaporize at a whim.

RTEXT is "live", it updates the date and time continuously.  That's not what our stamp is for.  We want to know the last time the file was editted, not saved. (Also our stamp requires no outside text file)

Finally (and mostly) the stamp routine we're using has been in use considerably longer than rtext has been around.  That thread was just to make it update across all layouts at once.
Title: Global Attribute Update?
Post by: ELOQUINTET on February 23, 2005, 04:10:49 PM
understood, all valid points. when i try to do as you said i get this though, you know why?

Command: (changeatt ent <dpk> <dpp>)
; error: bad argument type: lentityp nil
Title: Global Attribute Update?
Post by: CADaver on February 23, 2005, 10:36:06 PM
Quote from: ELOQUINTET
understood, all valid points. when i try to do as you said i get this though, you know why?
Command: (changeatt ent <dpk> <dpp>)
; error: bad argument type: lentityp nil


Okay, first understand that CHANGEATT is a subroutine that needs to be run "inside" another routine.  In that routine you define "ENT".  Look at the sample code below; CADAVER is the main routinie that collects data then calls the subroutine changeatt.  ENT is defined by:

Code: [Select]
((setq sset (ssget "X" '((2 . "TITLE") (66 . 1))))
         (setq a 0)
         (repeat (sslength sset)
           (setq ent (ssname sset a)
                 a   (1+ a)
           )


It finds the blocks called "TITLE", then steps through them one at a time (using A and A+1).  One at a time, it sets ENT with:
 setq ent (ssname sset a)

Look back below. Once ENT is defined it is passed to CHANGEATT along with a known attribute tag name "DRAWN_BY" and a new value for that tag "CADAVER" like this;
(changeAtt ent "DRAWN-BY" "CADaver")

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Code: [Select]
(defun changeAtt (ent tag val / entl ins)
  (setq ins ent)
  (while (and ent
           (/= "SEQEND" (cdr (assoc 0 (setq entl (entget ent))))))
    (if (and (= (cdr (assoc 0 entl)) "ATTRIB")
             (= (cdr (assoc 2 entl)) tag))
      (entmod (subst (cons 1 val) (assoc 1 entl) entl)))
    (setq ent (entnext ent)))
  (entupd ins)
)

(defun C:CADaver ()
  (cond ((setq sset (ssget "X" '((2 . "TITLE") (66 . 1))))
         (setq a 0)
         (repeat (sslength sset)
           (setq ent (ssname sset a)
                 a   (1+ a)
           )
           (changeAtt ent "DRAWN-BY" "CADaver") ;<- change value
         )
        )
  )
  (princ)
)


~~~~~~~~~~~~~~~~~~~~~~~~~~

Now you need to modify the routine c:CADAVER above to find your block name, instead of "TITLE", and use your attribute tag name, instead of "DRAWN-BY", and fill in your new value instead of "CADaver".

Now, everyone here knows I'm a lisp hack at my very best, so my description may leave a lot to be desired.  Maybe one of the real gurus around here (Yo, Mark, Stig, CAB, Daron, anybody) could flesh it out a little better.
Title: Global Attribute Update?
Post by: Kerry on February 23, 2005, 11:41:16 PM
If you prefer the activeX stuff, Something like this may suit you ..

If you feed it attribute tags that dont exist, it just chages the ones it can ..
Code: [Select]

(defun C:DrawnByMe (/ Index SSET)
  (cond ((setq sset (ssget '((2 . "TITLE") (66 . 1))))
         (setq Index -1)
         (repeat (sslength sset)
           (SetAttVals
             (vlax-ename->vla-object (ssname sset (setq Index (1+ Index))))
             (list (cons "DRAWN-BY" "ME")
                   (cons "DATE" "TODAY"))
           )
         )
        )
  )
  (princ)
)

(defun SetAttVals (oBlockref dotPairList / AttVal)
  (mapcar
    '(lambda (Attrib)
       (if (setq
             AttVal (cdr (assoc (vla-get-tagstring Attrib) dotPairList))
           )
         (vla-put-textstring Attrib AttVal)
       )
     )    
    (vlax-invoke oBlockref 'GetAttributes) ; saves a translation
   
  )
  (vla-update oBlockref)
  (princ)
)


Edit: What spell checker ?
Title: Global Attribute Update?
Post by: Kerry on February 23, 2005, 11:57:39 PM
... and then there's the complimentary routine :
Code: [Select]

(defun GetAttVals (oBlockref)
 (mapcar
 '(lambda (Attrib)
   (cons (vla-get-TagString Attrib)
         (vla-get-TextString Attrib)
   )
  )
  (vlax-invoke oBlockref 'GetAttributes)
 )
)


Used like this [ note the ":S" for single selection ]
Code: [Select]
(if (setq sset (ssget ":S" '((2 . "TITLE") (66 . 1))))
  (GetAttVals (vlax-ename->vla-object (ssname sset 0)))
)

Returns ALL the attribute tags, and their values
( ("DWG" . "TEST-001")("REVISION" . "P1") ("DRAWN-BY" . "ME") ("DATE" . "TODAY") )
Title: Global Attribute Update?
Post by: Jeff_M on February 24, 2005, 01:15:13 AM
Well I don't know how I missed this thread until now. And just my luck that Kerry has posted something quite similar (read "nearly identical")  to what I use. But I will post what I use just because.....  :D
Code: [Select]

;; Function to synchronize attributes of a given block, only those included in
;; the list will be updated
;; usage- (global_atts "myblock" *att_list*)
;; *att_list* as returned (or in the same form as) by the second routine,
;; "make_att_list"
;; Author: Jeff Mishler
;; Date 1/11/05
(defun global_atts (bname attlist)
  (if (setq ss (ssget "x" (list '(0 . "INSERT")(cons 2 bname)'(66 . 1))))
    (progn
      (setq count -1)
      (while (< (setq count (1+ count)) (sslength ss))
(setq blk (vlax-ename->vla-object (ssname ss count))
     atts2 (vlax-invoke blk "getattributes")
     )
(foreach att2 atts2
 (foreach att1 attlist
   (if (= (car att1)(vla-get-tagstring att2))
     (progn
(vla-put-textstring att2 (cdr att1))
(vla-update att2)
     )
   )
 )
(vla-update blk)
)
      )
    )
  )

  ;; for use with the global_atts function above
(defun make_att_list (/ ent obj atts)
  (and (setq ent (car (entsel "\nSelect block to log attributes for: ")))
       (setq obj (vlax-ename->vla-object ent))
       (if (and (vlax-property-available-p obj 'hasattributes)
(eq (vla-get-hasattributes obj) :vlax-true))
(progn
  (setq atts (vlax-invoke obj 'getattributes))
  (foreach att atts
    (setq *att_list* (cons
(cons
 (vla-get-tagstring att)
 (vla-get-textstring att)
 )
*att_list*
)
  )
    )
  )
)
       )
  )
 
Title: Global Attribute Update?
Post by: Jeff_M on February 24, 2005, 01:16:56 PM
I knew I shouldn't be posting at the end of a 16 hour day. I tried to fing the following lisp to post and just couldn't locate it. Now, this moning, I found it right off the bat.

This one fills out the sheet name, sheet number and total number of sheets, based on the Layout tab names. I know it works with my title block, but it wouldn't take much to tweak it to yours.....
Code: [Select]

;|Insert a title block into all PaperSpace Layout Tabs,
  all at 0,0,0 & 0 deg. rotation, use attlist for filling
  attribute values. attlist format:
  (("tagstring" . "value")("tagstring" . "value"))
  Routine will automagically input values for attributes of a
  Title block that contains attributes with tagstrings of
  "NO", "SHEETS" & "SHEET_NAME" by using the Tab order number
  for the "NO" (sheet number), the total number of tabs minus 1 (the
  Model tab) for "SHEETS" (number of sheets), and the Tab name for the
  "SHEET_NAME". By including a listing in the attlist for any, or all,
  of these you can overwrite what is placed there.
  by Jeff Mishler, April 2004
|;

(defun title2tabs (bname attlist / lays blk newblk tag)
  (setq lays (vla-get-layouts
      (vla-get-activedocument
(vlax-get-acad-object)))
)
  (if (not (tblsearch "block" bname))
    (progn
      (princ "\nBlock not found, please select block: ")
      (setq bname
    (getfiled "Block Selection for Tab Insert" bname "dwg" 0))
      )
    )
  (vlax-for x lays
    (if (not (or (= "Model" (vla-get-name x))
(= (getvar "CTAB") (vla-get-name x)))
    )
      (progn
(setq blk (vla-get-block x))
(setq newblk nil)
(vlax-for ent blk
 (if (and (eq (vla-get-objectname ent) "AcDbBlockReference")
  (eq (vla-get-name ent) bname)
  )
   (setq newblk ent)
   )
 )
(if (not newblk)
 (setq newblk (vlax-invoke-method
      blk
      'insertblock
      (vlax-3d-point
'(0.0 0.0 0.0))
      bname 1.0 1.0 1.0 0.0)
     )
 )
 (if (= (vla-get-hasattributes newblk) :vlax-true)
   (progn
     (setq atts (vlax-safearray->list
  (vlax-variant-value
    (vla-getattributes newblk))))
     (foreach att atts
(setq tag (vla-get-tagstring att))
(cond ((= tag "NO")
      (vla-put-textstring att (itoa (vla-get-taborder x))))
     ((= tag "SHEETS")
      (vla-put-textstring att (itoa (1- (vla-get-count lays)))))
     ((= tag "SHEET_NAME")
      (vla-put-textstring att (strcase (stripstr (vla-get-name x) "-"))))
     ((assoc tag attlist)
      (vla-put-textstring att (cdr (assoc tag attlist))))
     (t ;no default input, add marker text
      (vla-put-textstring att "????")
 )
)
     )
   )
)
      )
      )
    )
  (princ)
  )

;;following code to help facilitate creating attlist for use in title2tabs
(defun make_attlist (bname / taglist str)
  (vlax-for x (vla-item (vla-get-blocks *doc*) bname)
    (if (= (vla-get-objectname x) "AcDbAttributeDefinition")
      (setq taglist (cons (vla-get-tagstring x) taglist))
      )
    )
  (foreach x taglist
    (setq str (getstring t (strcat "\nValue to use for attribute tag \""
  x
  "\": ")))
    (if (not (= str ""))
      (setq attlist (cons (cons x str) attlist))
      )
    )
  attlist
  )
;; or select an existing block
(defun get_attlist (/ ss obj)
  (princ "\nSelect Title block to gather Attribute data from: ")
  (if (setq ss (ssget ":S"'((0 . "INSERT"))))
    (progn
      (setq obj (vlax-ename->vla-object (ssname ss 0)))
      (if (eq :vlax-true (vla-get-hasattributes obj))
(progn
 (foreach att (vlax-invoke obj "getattributes")
   (setq attlist (cons (cons (vla-get-tagstring att)
     (vla-get-textstring att))
attlist))
   )
 )
)
      )
    )
  )

;|code to parse a string....
   (setq str "wp-property")
   (stripstr str "-")
   returns: "property"
 |;
(defun stripstr (str itm / pos)
  (setq pos (vl-string-search itm str))
  (if (not pos) (setq pos -1));set pos incase item looking for not found not found
  ;increment pos by 2, 1 for 0 vs 1 based index, 1 for next character
  (substr str (+ pos 2))
  );
Title: Global Attribute Update?
Post by: TimSpangler on February 24, 2005, 03:01:34 PM
Thanks Jeff,

I haven't tried it yet but, I have been working on some of the code for the past 2 Night (total of about 1 hrs,  I have a 4 year old :roll:  :wink: )  I have a larger routine in mind for inserting addind, and updating info in the title block so I have alittle work ahead of me.

I truly apprieciate the efforts from everyone, Thanks again