TheSwamp

Code Red => AutoLISP (Vanilla / Visual) => Topic started by: Biscuits on January 03, 2006, 02:21:50 PM

Title: Attribute change
Post by: Biscuits on January 03, 2006, 02:21:50 PM
This macro allows me to update any attribute I mouse-pick to read "2006 C-n-R CORPORATION" (an attribute used for our copyright year). This will work on attributes burried within blocks that are embedded within blocks. Unfortunately some of our titleblocks were set up this way. This is the only "quick" routine I've been able to find. I'm looking for a simple way to find this attribute and automatically update it to the current year without actually selecting the attribute in question. The tag used is "copyright" or "copyrightyear" depending which titleblock was used. We are still using ACAD 2002. We are dealing with thousands of drawings each year that require an update for this copyright year. Any ideas out there?
Thanks and Happy New Year!

Code: [Select]
_-ATTEDIT;;;;;\ _VALUE _REPLACE $(EVAL, 2006 C-n-R CORPORATION)^H;;
Title: Re: Attribute change
Post by: uncoolperson on January 03, 2006, 02:27:31 PM
Code: [Select]
(DEFUN attmod (tagstring textstring / block-ent attribute-value attribute-list)
  (COMMAND "-LAYER" "u" "border" "")
  (SETQ block-ent (CAR (LAST (NENTSELP '(29 0 0)))))
  (SETQ attribute-list
(VLAX-SAFEARRAY->LIST
   (VLAX-VARIANT-VALUE
     (VLA-GETATTRIBUTES
       (VLAX-ENAME->VLA-OBJECT block-ent)
     )
   )
)
  )
  (FOREACH attribute attribute-list
    (IF (= tagstring (VLA-GET-TAGSTRING attribute))
      (VLA-PUT-TEXTSTRING attribute textstring)
    )
  )
  (COMMAND "-layer" "lo" "border" "")
)

I use something like this... the border layer is always locked... and the corner of it is at (29 0 0)
it's not clean or perfect, but it works


Edit: the above code doesn't handle nested attributes... jeez i should read things more thoroughly
Title: Re: Attribute change
Post by: Biscuits on January 03, 2006, 02:42:48 PM
Thanks for the quick response, UNCOOL. But I have no clue how to use your coding
Title: Re: Attribute change
Post by: uncoolperson on January 03, 2006, 02:59:40 PM
you're wanting to use lisp right? if not just ignore all this.

change '(29 0 0) to some point that only your title block would be at '(0 0 0) is pretty good too
this is assuming your attributes are part of your title block

if your title block layer (the one containing the stuff we want to play with) is always locked (like mine) change border in these two lines to whatever you border layer is

Code: [Select]
(COMMAND "-LAYER" "u" "border" "")
(COMMAND "-layer" "lo" "border" "")

otherwise delete them

then to change and attribute with the tag of "DATE" to today use
(attmod "DATE" "01/03/06")
Title: Re: Attribute change
Post by: deegeecees on January 03, 2006, 03:30:35 PM
Here is something similar. It handles embedded entities.

Code: [Select]
(defun c:underliner ()
(setq en1 (nentsel "\nPlease choose an object:" ))
(setq en1-2 (car en1))
(setq en3 (entget (car En1)))
(setq en4 (cdr (assoc 1 en3)))
(setq txt1 (strcat "%%u" en4));;;;<-------Just change %%u to C-n-C Corp...

   (setq en3
                   (subst(cons 1 txt1)
                         (assoc 1 en3)
                         en3))
       (entmod en3)
        (entupd en1-2)
(command "regen")
(princ)
)

You could use a number of ways to accomplish your task. Use something like this for selecting the right attribute:

Code: [Select]
(SETQ isrev11 (SSGET "X" '((2 . "rev-att-cntr"))));;<------------change rev-att-cntr to your block name
(IF isrev11
(PROGN
(setq qtyisrev (sslength isrev11))
(if (= 1 qtyisrev)
(progn
(SETQ isrev21 (SSNAME isrev11 0))
(setq isrev2-1 (entnext isrev21));;;;;;;;;coding keeps going but had to cut off for sake of making sense.

Of course I may be confusing the issue here, so I'll stop now. If you are totally confused, let me know, and I'll try to spend more time on it for you.


Ok, while I was writing this, uncool posted something that needs to be clarified before we keep going. This is the AutoLISP forum, so it is assumed that by posting a question here it is Lisp oriented. What are you trying to do Mr. Buscuits? Please elaborate a bit.


Title: Re: Attribute change
Post by: Biscuits on January 03, 2006, 04:13:44 PM
Ok Deegeecees. Here goes. Using ACAD 2002, we have tons of existing drawings that use one of two title blocks. These title blocks contain an attribute used to indicate the year (at the time) & copyright. The tags for these would either be "copyright" or "copyrightyear". As each new year comes about, this attributes value needs updating when older drawings get modified. Example: "2005 C-n-R Corporation" nows needs to read "2006 C-n-R Corporation"
As you can imagine, we go through this every year. Problem is, at one time, a large portion of existing drawings had the titleblock attribute in question embedded (nested?) within another block. In recent drawings, embedding within blocks was corrected to just typical attributes. My macro as earlier posted, would allow next-to-automatic updating for this attribute (embedded or not). All I had to do was pick the button containing the macro then select each attribue requiring the change. We use multiple titleblocks within a single drawing  and almost always use model space (very seldom layouts). I'm trying to avoid selecting each attribute requiring the change. I admit I'm lazy and looking for a simple means. I don't care if lisp, VBA, or diesel is used. I have toyed with lisp but get nowhere with this one. I'm not sure what I need to complete Uncoolperson's routine. I will experiment with your coding and see what happens.
Thanks alot
Title: Re: Attribute change
Post by: deegeecees on January 03, 2006, 04:28:46 PM
You are welcome, and thanks for the elaboration.

The first thing that came to mind was "XREF". I cannot tell you how invaluable this little aspect of AutoCAD is. I think they made it just for your situation. If you have an xrefed titleblock, it is very easy to change the initial titleblock drawing, then all other drawings that reference this will update automatically.

What I would do is this:

1. Create a copy of the titleblock (only static entites, or entities that will not change from dwg to dwg).
2. Copy/paste to original coordinates the dynamic entities (basically, the attributes that will change from dwg to dwg).
3. Write a routine that will replace the old inserted block with the new xrefed one and the attributes.

Does this sound like something you would like to do?
Title: Re: Attribute change
Post by: Biscuits on January 03, 2006, 04:47:51 PM
I agree with you DeeGeeCee. We thought about XRef's and for the life of me I can not remember why management said no to the idea. I tried your "underliner" routine and it works great. It essentially does the same thing as my macro. Simply put, I'm trying to eliminate having to actually select each attribute requiring the change (especially in the case of multiple titleblocks). Like I said I'm lazy and going for further automation.
Thanks again for your responses.
Title: Re: Attribute change
Post by: uncoolperson on January 03, 2006, 04:52:47 PM
if your attributes are ALWAYS at the same location you could throw attedit command some pick points

(now hows that for dangerous....)
Title: Re: Attribute change
Post by: deegeecees on January 03, 2006, 04:55:13 PM
if your attributes are ALWAYS at the same location you could throw attedit command some pick points

(now hows that for dangerous....)

Cookin with fire!

Ok, well my next suggestion is to take the above posted code and add a while loop to it to step through the blocks entities until it finds the correct one, then change it. To automate all this just add a function that calls it in an .MNL file or ACAD200X.DOC.
Title: Re: Attribute change
Post by: Biscuits on January 03, 2006, 05:00:41 PM
That's livin on da edge there UNCOOL! Nice try though.

DeeGeeCees yer talkin beyond my skill level.

By the way, what is that Avatar yer using?
Title: Re: Attribute change
Post by: T.Willey on January 03, 2006, 05:11:05 PM
If you want it animated, then you need to provide the names of the title blocks that you use.  Each one.  The main one that is in the drawing, and the ones that are nested (embedded) in them, until you get to the block where the attributes are.
Title: Re: Attribute change
Post by: dan19936 on January 03, 2006, 05:34:09 PM
<snip>This will work on attributes burried within blocks that are embedded within blocks.

I'm not sure I understand. When I use ATTEDIT on an attribute in a block in a block, I get the error "That block has no editable attributes".

Wish I had a direct solution, but the best I can do it search my list archive (using TextPad wildcard ssget.*insert)
The following code had an attribute search & replace function

Code: [Select]
;;; From: Jon Fleming (jonf@fleming-group.com)
;;; Subject: Re: Titleblock & updating attribute woes.
;;; Newsgroups: autodesk.autocad.customization
;;; Date: 2001-12-22 05:38:18 PST
(defun UpdatePlotDateReactor (CallingReactor CommandList /
                              TitleBlockEList AttribDXFList SelSet
                              Counter DateWasUpdated DateTime
                              DrawingFileName
                             )
  ;; If we are about to run the PLOT commmand ...
  (if (= "PLOT" (car CommandList))
    (progn
      ;; Initialize a flag for how many plot dates were changed
      (setq DateWasUpdated 0
            ;; Get the current date as a string
            DateTime       (menucmd "M=$(edtime,$(getvar,date),M/D/YY HH:MM:SSAM/PM)")
      ) ;_ end setq
      ;; Get the file ename if there is one
      (if (= (getvar "DWGTITLED") 0)
        (setq DrawingFileName "<none>")
        (setq DrawingFileName (getvar "DWGNAME"))
      )
      ;; If there is a title block (a BLOCK, named Title Block, with
      ;; attributes)
      (if (setq SelSet (ssget "X" '((0 . "INSERT") (2 . "A1-TITLE") (66 . 1))))
        (progn
          (setq Counter (sslength SelSet))
          ;; For all title blocks (may be a multiple sheet drawing)
          (while (<= 0 (setq Counter (1- Counter)))
            ;; Get the title block
            (setq TitleBlockEList (entget (ssname SelSet Counter))
                  ;; Look for the plot date attribute
                  AttribDXFList (get_subentity
                                    TitleBlockEList
                                    '(2 . "PLOT_DATE_&_TIME")
                                  ) ;_ end get_subentity
            ) ;_ end setq
            ;; If the attribute was found (if it wasn't found,
            ;; AttribDXFList will contain a SEQEND entity) ...
            (if (= "ATTRIB" (cdr (assoc 0 AttribDXFList)))
              ;; If its value is out of date ...
              (if (/= DateTime (cdr (assoc 1 AttribDXFList)))
                (progn
                  ;; Update it
                  (entmod
                    (list
                      (assoc -1 AttribDXFList)
                      (cons 1 DateTime)
                    ) ;_ end list
                  ) ;_ end entmod
                ) ;_ end progn
              ) ;_ end if
            ) ;_ end if
            ;; Look for the file name attribute
            (setq AttribDXFList (get_subentity
                                    TitleBlockEList
                                    '(2 . "CAD_FILENAME")
                                  ) ;_ end get_subentity
            ) ;_ end setq
            ;; If the attribute was found (if it wasn't found,
            ;; AttribDXFList will contain a SEQEND entity) ...
            (if (= "ATTRIB" (cdr (assoc 0 AttribDXFList)))
              ;; If its value is out of date ...
              (if (/= DrawingFileName (cdr (assoc 1 AttribDXFList)))
                (progn
                  ;; Update it
                  (entmod
                    (list
                      (assoc -1 AttribDXFList)
                      (cons 1 DrawingFileName)
                    ) ;_ end list
                  ) ;_ end entmod
                  ;; Update the screen
                  (entupd (cdr (assoc -1 TitleBlockEList)))
                  ;; Update the flag for how many we've changed
                  (setq DateWasUpdated (1+ DateWasUpdated))
                ) ;_ end progn
              ) ;_ end if
            ) ;_ end if           
          ) ;_ end while
        ) ;_ end progn
      ) ;_ end if
      ;; If we did any updates, tell the user
      (if (/= 0 DateWasUpdated)
        (if (< 1 DateWasUpdated)
          (progn
            (prompt
              (strcat "\nUpdated \"Plotted\" in "
                      (itoa DateWasUpdated)
                      " title blocks"
              ) ;_ end strcat
            )
            (princ)
          )
          (progn (prompt
                   "\nUpdated \"Plotted\" in the title block"
                 )
                 (princ)
          )
        ) ;_ end if
      ) ;_ end if
    ) ;_ end progn
  ) ;_ end if
  (prin1)
) ;_ end defun

Title: Re: Attribute change
Post by: deegeecees on January 03, 2006, 05:36:33 PM
Wow! Thats some great notation. Jon Fleming, my hat goes off to you wherever you are.
Title: Re: Attribute change
Post by: CAB on January 03, 2006, 05:49:23 PM
Give this a try.
Code: [Select]
;;=======================[ cUpdate.lsp ]=======================
;;; Author: CopyrightŠ 2006 Charles Alan Butler
;;; Version:  1.0 Jan. 03, 2006
;;; Purpose: To update attributes in a drawing, nested blocks & xref
;;;          Ignores locked or Frozen layers
;;; Sub_Routines: -None
;;; Requirements: -None
;;; Returns: -None
;;;==============================================================
;;
(defun c:cupdate (/ ss ent obj attributes att)
  (setq newtext "2006 C-n-R CORPORATION")
  (setq ss (ssget "_X" '((0 . "INSERT"))))
  (setq i -1)
  (if ss
    (while (setq ent (ssname ss (setq i (1+ i))))
      (if (and (setq obj (vlax-ename->vla-object ent))
               (= (vla-get-objectname obj) "AcDbBlockReference")
               (= (vla-get-hasattributes obj) :vlax-true)
          )
        (progn
           (setq attributes (vlax-invoke obj 'getattributes))
           (foreach att attributes
             (if (or (= "COPYRIGHT" (vla-get-tagstring att))
                     (= "COPYRIGHTYEAR" (vla-get-tagstring att))
                 )
               (progn
                 (vla-put-textstring att newtext)
                 (vla-update att)
               )
             )
           )
        )
      )
    )
  )

  (or *doc* (setq *doc* (vla-get-activedocument (vlax-get-acad-object))))
  (if (< 0 (vla-get-count (setq blks (vla-get-blocks *doc*))))
    (progn
      (vlax-for blk blks
        (if (/= (vla-get-name blk) "*Model_Space")
          (vlax-for ent blk
            (if (and (vlax-property-available-p ent 'hasattributes)
                     (= (vla-get-hasattributes ent) :vlax-true)
                )
              (progn
                (setq attributes (vlax-invoke ent 'getattributes))
                (foreach att attributes
                  (if (or (= "COPYRIGHT" (vla-get-tagstring att))
                          (= "COPYRIGHTYEAR" (vla-get-tagstring att))
                      )
                    (progn
                      (vla-put-textstring att  newtext)
                    )
                  )
                )
              )
            )
          )
        )
      )
      (vla-regen *doc* acactiveviewport)
    )
  )
  (princ)
)
(prompt "\nCopyright Update Loaded, Enter cupdate to run.")
(princ)
Title: Re: Attribute change
Post by: Biscuits on January 03, 2006, 05:56:41 PM
Cab your awsome! Just what I was Looking for! Works perfect! Many thanks!

And many thanks to all who have tried to help!!!!!!!!!

The Swamp Rocks!!!!!!!!
Title: Re: Attribute change
Post by: deegeecees on January 03, 2006, 05:59:27 PM
By the way, what is that Avatar yer using?

Its Lil' Ozzie, my first 3DStudio creation.
Title: Re: Attribute change
Post by: deegeecees on January 03, 2006, 06:02:30 PM
Yes, CAB you truly do rock! I'm gonna have to give you a C- on your notation though...

<MP>Adusting score card</MP>
Title: Re: Attribute change
Post by: T.Willey on January 03, 2006, 06:06:11 PM
Nice one CAB.  I was wondering how you would get the attribute if it was nested.  I see that you have to go through the blocks collection, and edit it there.  Nice to know.
Title: Re: Attribute change
Post by: Jeff_M on January 03, 2006, 06:28:45 PM
Alan, I'd only advise 2 things.......(ssget "x") obtains the desired objects on ALL tabs, so when you step through the Blocks collection in place of the Model_Space check I would omit those that have the IsLayout = true. Otherwise you are stepping through those blocks twice.
Second, you could replace this:
(and (setq obj (vlax-ename->vla-object ent))
               (= (vla-get-objectname obj) "AcDbBlockReference")
               (= (vla-get-hasattributes obj) :vlax-true)
          )
with
(setq obj (vlax-ename->vla-object ent))

by filtering your SS like so:
(setq ss (ssget "_X" '((0 . "INSERT")(66 . 1)))

The 66 . 1 will filter for attributed blocks so no att check is needed.

just my 2 cents.....
Title: Re: Attribute change
Post by: Kerry on January 03, 2006, 06:31:31 PM
Editted : ^ ^ What he said ^ ^
Jeff types too quickly for me ..

Nice job Alan.
Title: Re: Attribute change
Post by: CAB on January 03, 2006, 06:44:34 PM
Yes, CAB you truly do rock! I'm gonna have to give you a C- on your notation though...

<MP>Adusting score card</MP>
What notation :-D
Title: Re: Attribute change
Post by: CAB on January 03, 2006, 07:00:11 PM
OK, thanks for the info Jeff.
I'm starting to understand a little more on the block collections
Here is the revised code.

Code: [Select]
;;=======================[ cUpdate.lsp ]=======================
;;; Author: CopyrightŠ 2006 Charles Alan Butler
;;; Version:  1.1 Jan. 03, 2006
;;; Purpose: To update attributes in a drawing, nested blocks & xref
;;;          Ignores locked or Frozen layers
;;; Sub_Routines: -None
;;; Requirements: -None
;;; Returns: -None
;;;==============================================================
;;
(defun c:cupdate (/ ss ent obj att blks newtext taglist)
  (setq newtext "2006 C-n-R CORPORATION"
        taglist '("COPYRIGHT" "COPYRIGHTYEAR"))
  (or *doc* (setq *doc* (vla-get-activedocument (vlax-get-acad-object))))
  (if (< 0 (vla-get-count (setq blks (vla-get-blocks *doc*))))
    (progn
      (vlax-for blk blks
        (vlax-for ent blk
          (if (and (vlax-property-available-p ent 'hasattributes)
                   (= (vla-get-hasattributes ent) :vlax-true)
              )
            (progn
              (foreach att (vlax-invoke ent 'getattributes)
                (if (member (vla-get-tagstring att) taglist)
                  (vla-put-textstring att newtext)
                )
              )
            )
          )
        )
      )
      (vla-regen *doc* acactiveviewport)
    )
  )
  (princ)
)
(prompt "\nCopyright Update Loaded, Enter cupdate to run.")
(princ)
Title: Re: Attribute change
Post by: LE on January 03, 2006, 07:12:56 PM
Are almost ALL the blocks in the collection in need to be updated?
Why not making a normal selection set with SSGET and the filter, and then just use the active selection set ?
Title: Re: Attribute change
Post by: CAB on January 03, 2006, 07:16:40 PM
Well the attribute in question could be in a block
or in a block within a block
or in a block within an xref

So i had a problem with the block within an xref. That is getting to it with ssget.
ssget finds the xref but not the nested block with the attribute.
Title: Re: Attribute change
Post by: LE on January 03, 2006, 07:23:07 PM
Well the attribute in question could be in a block
or in a block within a block
or in a block within an xref

So i had a problem with the block within an xref. That is getting to it with ssget.
ssget finds the xref but not the nested block with the attribute.

I see it now , sorry...
Title: Re: Attribute change
Post by: CAB on January 03, 2006, 07:38:29 PM
No problem Luis.

Thanks all, I can't take all the credit.
I borrowed code from Jeff's c:txt2std routine
and some from Kerry's routines. :)
Title: Re: Attribute change
Post by: Jeff_M on January 03, 2006, 07:51:49 PM
Well the attribute in question could be in a block
or in a block within a block
or in a block within an xref

So i had a problem with the block within an xref. That is getting to it with ssget.
ssget finds the xref but not the nested block with the attribute.
I'm having a hard time understanding this part......If it's in an Xref you can't permanently change that  unless you edit the Xref drawing..... and even if you could, I would still use the (ssget) to get the Model/Paper space inserts w/attributes, then loop through the blocks collection examining only those non-Layout blocks. If you want to change the Xref, ObjectDBX will need to be added.......

Or am I missing something obvious..... ?
Title: Re: Attribute change
Post by: CAB on January 03, 2006, 08:09:55 PM
I doubt you are missing anything. I didn't check the xref to see if the change was in that drawing.
I could not get the ssget to pick up the nested block. The test I did rejected the block as not having attributes.
I'll have to get back to this tomorrow when I can dig a little deeper to understand the non-layout issue.
Thanks Jeff
Title: Re: Attribute change
Post by: CAB on January 03, 2006, 10:03:07 PM
OK, Jeff.
If I do it this way with (if (= (vla-get-islayout blk) :vlax-false)
the plain blocks with attributes are overlooked as they are within the
model space block.
The nested block with attributes within a block and the xref are updated.
So without the exclusion the routine looks into each model & PS block to get
each insert with attributes.
What is the concern doing it this way? Too slow in a large drawing?

Code: [Select]
(defun c:cupdate (/ ss ent obj att blks newtext taglist)
  (setq newtext "2006 C-n-R CORPORATION"
        taglist '("COPYRIGHT" "COPYRIGHTYEAR"))
  (or *doc* (setq *doc* (vla-get-activedocument (vlax-get-acad-object))))
  (if (< 0 (vla-get-count (setq blks (vla-get-blocks *doc*))))
    (progn
      (vlax-for blk blks
         (if (= (vla-get-islayout blk) :vlax-false) ; exclude model & PS blockobjects   <-----<<<<< Oops , had this in the wrong spot
       (vlax-for ent blk
           (if (and (vlax-property-available-p ent 'hasattributes)
                   (= (vla-get-hasattributes ent) :vlax-true)
              )
            (progn
              (foreach att (vlax-invoke ent 'getattributes)
                (if (member (vla-get-tagstring att) taglist)
                  (vla-put-textstring att newtext)
                )
              )
            )
          )
         )
        )
      )
      (vla-regen *doc* acactiveviewport)
    )
  )
  (princ)
)
(prompt "\nCopyright Update Loaded, Enter cupdate to run.")
(princ)

Edit: move the if statement.
Title: Re: Attribute change
Post by: Kerry on January 03, 2006, 10:19:33 PM
Design question :

If you change the attribute value in the block definition in the BlockTable<collection> does it change all insert instances ?

Title: Re: Attribute change
Post by: CAB on January 03, 2006, 11:06:16 PM
I say no, the attribute values are unique to the INSERT.
Was that a trick question? :)

This is the way I think the routine is working
CASE 1
Code: [Select]
(vlax-for blk blks  ;  <---<<  this steps through the block collection
                           ;;  when *Model_Space or *Paper_Space is the block
   (vlax-for ent blk ; <----<<  this steps throught each item in model space and finds the INSERTS
                            ;;  then the attributes are updated <plain blocks with attributes>

CASE 2
Code: [Select]
(vlax-for blk blks  ;  <---<<  this steps through the block collection
                           ;;  when xref is the block
   (vlax-for ent blk ; <----<<  this steps throught each item in the xref and finds the INSERTS
                            ;;  then the attributes are updated <plain blocks with attributes>

CASE 3
Code: [Select]
(vlax-for blk blks  ;  <---<<  this steps through the block collection
                           ;;  when parentblock is the block
   (vlax-for ent blk ; <----<<  this steps throught each item in the parent and finds the INSERTS
                            ;;  then the attributes are updated <plain blocks with attributes>
I tested Case 3  to 3 levels deep & the attributes were updated.
Title: Re: Attribute change
Post by: CAB on January 03, 2006, 11:12:50 PM
Oh, I checked the actual xref drawing & the attributes are not updated. But Jeff new that already. :-)

So the Actual drawing of the two titleblocks will have to be updated with refedit or opened directly
and edited. Not a big deal as there are only two of them in this case.
But every thing in the drawings will be updated & the xref will be two, else you would have to
reload the xref to show the updated attributes. I guess that doesn't matter as they are reloaded
each time the drawing is opened, right?

Title: Re: Attribute change
Post by: Kerry on January 03, 2006, 11:19:33 PM
I say no, the attribute values are unique to the INSERT.
Was that a trick question? :)


Yes, sort of <a trick question> ..
The answer you gave meant that you weren't tricked  though.  :kewl:
Title: Re: Attribute change
Post by: Jeff_M on January 03, 2006, 11:24:22 PM
OK, Jeff.
If I do it this way with (if (= (vla-get-islayout blk) :vlax-false)
the plain blocks with attributes are overlooked as they are within the
model space block.
Yes, I know.....which is why I said I'd use it with the (ssget "x" '((0 . "INSERT")(66 . 1))) to select the attributes in Model/Paper space.....this saves having to step through every object in a large drawing (native, filtered selection sets are faster than stepping through each MS/PS block)

However....if you want to turn your main routine into a function that also handles ObjectDBX docs to work on the Xrefs, then forget that since ODBX doesn't allow SelSets anyway.

I've got an idea I'll post here in a bit.
Title: Re: Attribute change
Post by: Jeff_M on January 04, 2006, 12:21:00 AM
OK, here's a version that I believe will work with the Xrefs. I've not tested it so it may have faults but it appears sound to me.
Code: [Select]
See revised & tested code further on in this thread
Title: Re: Attribute change
Post by: CAB on January 04, 2006, 09:10:50 AM
Good morning Jeff, had to go to bed.
Wow, new territory for me the ObjectDBX.
I tested and found this line (vla-saveas odbx file) caused an 'Error saving File'
I commented it out and the routine finished with the plain blocked changed but
the nested block & of course the xref were unchanged.

Do I need to do anything special to enable the ObjectDBX are is it automatic?
Still using ACAD2000 for this test.
Title: Re: Attribute change
Post by: T.Willey on January 04, 2006, 11:29:37 AM
I remember hearing that using ObjectDBX with text, mtext or attributes has problems.  I think the problem was that they loose there alignment sometimes.  I remember trying to do an update title block routine with OBDX and ran into this, and it was confirmed with others one the another forum (acad customization at autodesk).  I think they said that Tony T. had a program to fix it, but that it wasn't available with later version of Acad.

My $00000.02
Title: Re: Attribute change
Post by: T.Willey on January 04, 2006, 11:39:15 AM
Jeff,
Would your routine fail when it ran into an xref within an xref?
After thinking about it, I don't think that is a problem.

The only problem I can see is if you have 3 (or more) drawings that reference each other, so a continout loop will occur.
Drawing A -> References Drawing B
Drawing B -> References Drawing C
Drawing C -> References Drawing A

I know you could take care of this it would just take more coding, but that is the only issue I can see, other than the one I pointed out about the alignment issue.
Title: Re: Attribute change
Post by: Biscuits on January 04, 2006, 12:04:54 PM
Wow I sure got some brain cell to fire up! None  of them mine.

Routine is working great CAB!

Thanks again
Title: Re: Attribute change
Post by: Jeff_M on January 04, 2006, 12:52:03 PM
OK, Good Morning Alan & Tim.....'twas a long night with an ill cat....
I did find an error in the RELOAD portion for the xref:
Code: [Select]
    (vl-catch-all-apply '(lambda () (vla-reload (vla-item (vla-get-blocks doc) (vla-get-name ent)))))
is what it needs to be.

Alan, if it makes it past the (setq odbx....) without error then you already have ObjectDBX registered. I will check if there is an issue with the SaveAs in R2000......wait, if the SYSVAR XLOADCTL is set to anything other than 2 it will probably cause this. Here's a version that first Unloads the Xref so it can be edited than Reloads it.
Code: [Select]
;;=======================[ cUpdate.lsp ]=======================
;;; Author: CopyrightŠ 2006 Charles Alan Butler
;;; Version:  1.11jm Jan. 03, 2006
;;; Purpose: To update attributes in a drawing, nested blocks & xref
;;;          Ignores locked or Frozen layers
;;; Sub_Routines: -None
;;; Requirements: - Acad Versions 2000-2002 must have ObjectDBX registered before running
;;; Returns: -None
;;;==============================================================
;; ObjectDBX added to edit Xrefs by Jeff Mishler
;;
(defun c:cupdate (/ ss ent obj att blks newtext taglist)
  (setq newtext "2006 C-n-R CORPORATION"
taglist '("COPYRIGHT" "COPYRIGHTYEAR")
  )
  ;; converted majority to function for recursive use with xrefs, jm
  (defun process_atts (doc / file odbx)
    (vlax-for blk (vla-get-blocks doc)
      (vlax-for ent blk
(if (and (vlax-property-available-p ent 'hasattributes)
(= (vla-get-hasattributes ent) :vlax-true)
    )
  (progn
    (foreach att (vlax-invoke ent 'getattributes)
      (if (member (vla-get-tagstring att) taglist)
(vl-catch-all-apply '(lambda ()
       (vla-put-textstring att newtext)
       ))
;;added catch-all to catch possible locked layer error, jm
      )
    )
  )
)
(if (and (vlax-property-available-p ent 'path)
(setq file (findfile (vla-get-path ent)))
(setq xrblk (vla-item (vla-get-blocks doc) (vla-get-name ent)))
)
  (progn
    (vla-unload xrblk)
    (setq odbx (if (< (atoi (setq oVer (substr (getvar "acadver") 1 2))) 16)
(vla-GetInterfaceObject (vlax-get-acad-object) "ObjectDBX.AxDbDocument")
(vla-GetInterfaceObject (vlax-get-acad-object) (strcat "ObjectDBX.AxDbDocument." oVer))
))
    (vla-open odbx file)
    (process_atts odbx)
    (vl-catch-all-apply '(lambda () (vla-saveas odbx file)))
    (vlax-release-object odbx)
    (vl-catch-all-apply '(lambda () (vla-reload xrblk)))
    )
  );;
      )
    )
  )
  (process_atts (vla-get-activedocument (vlax-get-acad-object)))
  (princ)
)
(prompt "\nCopyright Update Loaded, Enter cupdate to run.")
(princ)

Tim, the alignment problem is only with Attributes and only when you change the alignment. Just changing the value does not cause a problem, IIRC. I'm pretty sure that Autocad already prevents you from creating the Xrefs in a loop. Although a problem is encountered with nested Xrefs, which is why the Reload is wrapped by the (vl-catch-all-apply).....you can't reload a nested xref, only the parent xref.
Title: Re: Attribute change
Post by: T.Willey on January 04, 2006, 01:15:27 PM
Tim, the alignment problem is only with Attributes and only when you change the alignment. Just changing the value does not cause a problem, IIRC.
I just tested it, and it doesn't show right after you change the text also.  I change it with this routine.
Code: [Select]
(defun c:TestAttributes (/ dbxApp File)

(setq dbxApp (vla-GetInterfaceObject (vlax-get-Acad-Object) "ObjectDBX.AxDbDocument.16"))
(setq File (getfiled "" "" "dwg" 4))
(vla-Open dbxApp File)
(vlax-for i (vla-get-PaperSpace dbxApp)
 (if
  (and
   (= (vla-get-ObjectName i) "AcDbBlockReference")
   (= (vla-get-Name i) "3M-BORDER-E1")
  )
  (foreach ii (vlax-invoke i 'GetAttributes)
   (vla-put-TextString ii "This is a test")
  )
 )
)
(vla-SaveAs dbxApp File)
(vlax-release-object dbxApp)
(setq dbxApp nil)
(princ)
)
Attributes that are supposed to be middle justified, get change to show left justified.  You have to edit the attribute again to have it show the right justification again.  You can just edit the text with "ddatte" but you have to run that and actually change the text to have it update to the correct justification.

ps.  The code above will only work with A2k4 or above because of the call to ObjectDBX's interface object.
I'm pretty sure that Autocad already prevents you from creating the Xrefs in a loop.
This is true with only two references.  I'm talk about three (which I don't think would happen, but just wanted to point it out).
B -> into A
then A can not go into B because of circle reference.
But
A -> into C
C -> into B
B-> into A
This instance would not cause a circle reference because you are going from A to B to C then back to A then back into B etc...
Title: Re: Attribute change
Post by: CAB on January 04, 2006, 01:37:09 PM
That version worked on the plain blocks & the xref with XLOADCTL is set to 1
using ACAD2000 and no errors reported.

However the nested block attributes were not updated.
Title: Re: Attribute change
Post by: Jeff_M on January 04, 2006, 02:25:36 PM
I'm talk about three (which I don't think would happen, but just wanted to point it out).
B -> into A
then A can not go into B because of circle reference.
But
A -> into C
C -> into B
B-> into A
This instance would not cause a circle reference because you are going from A to B to C then back to A then back into B etc...
I just tried to do this and got a message box that "this was creating a circular reference, would I like to continue", I replied Yes and this is the result:
Code: [Select]
Command: _xref
Attach Xref "B": C:\Base Maps\Jeffs Test Files\XRefTest\B.dwg
"B" loaded.

Attach Xref "C": C:\Base Maps\Jeffs Test Files\XRefTest\C.dwg
"C" loaded.

Breaking circular reference from "C" to "current drawing".
All it did was remove the A reference from C.......So no, Acad keeps circular references from ever occurring.
Quote from: T.Willey
and it doesn't show right after you change the text also.
Right you are, I stand corrected.

Alan, the nested blocks in the drawing or in the Xref or all of them? Could you post the test drawings you are running this on?

And FWIW, based on what Biscuits originally posted, there isn't a need for the Xref portion anyway since they opted to NOT use them...........have we been trying to solve a problem that doesn't exist?
Title: Re: Attribute change
Post by: CAB on January 04, 2006, 02:38:56 PM
Sorry Jeff, the nested blocks were updated, just needed a regen to show it.

I guess I/we got off focus on the xref. Great solution though. 8-)

Thanks Jeff.
Title: Re: Attribute change
Post by: T.Willey on January 04, 2006, 02:45:50 PM
..have we been trying to solve a problem that doesn't exist?
I think so, but it was fun.

I don't think I am explaining clear enough.  I have three drawings with only one xref attached each.  A has B, B has C, and C has A.  If you check each drawing through the block collection, and then go to the next drawing if it's an xref, then in A you will go to B, and once in B you will go to C, and then once in C you will go to A, and then repeat until escape is hit.  I'm not talking about having two of the three xref'ed into each other, which I gather you thought I meant from your latest post.  Sorry if I wasn't clear.  Like I said I don't think this would every happen, so I probably wouldn't code for it, it just looks possible from your code.  I tried to run it here to test it, but it crashed.  Maybe because I'm using blank drawing.
Title: Re: Attribute change
Post by: Jeff_M on January 04, 2006, 05:02:07 PM
Tim, I created 3 drawings A B & C
In drawing C I referenced A, saved & closed C
In drawing B I referenced C, saved and closed B
In drawing A I referenced B and got the circular reference error that I posted.

Is this not what you described? This is with R2002, BTW.
Title: Re: Attribute change
Post by: T.Willey on January 04, 2006, 05:11:20 PM
Tim, I created 3 drawings A B & C
In drawing C I referenced A, saved & closed C
In drawing B I referenced C, saved and closed B
In drawing A I referenced B and got the circular reference error that I posted.

Is this not what you described? This is with R2002, BTW.

That is exactly what I was talking about.  That is weird because when I do it in mine I don't get that message.  The only thing I can think of that wuold affect it is, do you attach or overlay?  I use overlay.
Title: Re: Attribute change
Post by: Greg B on January 04, 2006, 05:18:33 PM
You all know how smart I am in this aspect, but reading through made me want to ask a question.

The routine is set up to find a certain attribute and change it to what you want.  In the case of the circular reference, once the routine changed the attribute value it would not find it again on the return circle and would then continue on?
Title: Re: Attribute change
Post by: T.Willey on January 04, 2006, 05:26:31 PM
The routine is set up to find a certain attribute and change it to what you want. In the case of the circular reference, once the routine changed the attribute value it would not find it again on the return circle and would then continue on?

It would find it again.  It looks for tag names, not attribute values.  It most likely will be in a different block.
They way Jeff did it:
It looks through the block collection
When if finds a block that has attributes, it checks to see if any of the attributes match the list of tag strings.
If it does, then it puts in the new value.
If it finds and xref, it starts to search the block collection of that xref repeating the steps above.

Then my quesion was what started the discussion on circular references.  If three (or more) drawings xref'ed each other, then it would stay in the loop forever until someone hit escape because it would seach the xref's that are found within xref's etc....

With Jeff's setup, it seems that that couldn't happen, but with mine it looks as if it could.

Hope that makes it a little clearer.?
Title: Re: Attribute change
Post by: Greg B on January 04, 2006, 05:28:59 PM
Ok...what does Jeff's routine look for that breaks the circle?

I would assume you add something to the nature of an IF THEN statement so it looks for specific strings within the block.  Would make the routine more widely useable by more then one person.  Nothing hard coded.
Title: Re: Attribute change
Post by: T.Willey on January 04, 2006, 05:35:34 PM
Ok...what does Jeff's routine look for that breaks the circle?
Nothing.  Just that the way his Acad is set up, it won't let that situation happen.  You could add some stuff to it to check it, but the OP doesn't need it.  And it is pretty unlikely that the instance I mentioned would happen.  The way he set it up is to look through the block collection.  Once it looks at all the information stored there, then it finishes by itself.

I would assume you add something to the nature of an IF THEN statement so it looks for specific strings within the block. Would make the routine more widely useable by more then one person. Nothing hard coded.
What comes to mind first, would be to set up a list of all the draiwngs that it checks, if the xref is in the list, then don't proceed with checking, if it's not, then add it, and proceed to check it.  That is how I think I would do it.
Title: Re: Attribute change
Post by: Jeff_M on January 04, 2006, 05:53:22 PM
What comes to mind first, would be to set up a list of all the draiwngs that it checks, if the xref is in the list, then don't proceed with checking, if it's not, then add it, and proceed to check it. That is how I think I would do it.
I thought about adding something like this since an Xfref can be inserted multiple times and there would be no need to edit the Xref drawing more than once. I just decided to let it go when I recalled seeing that the OP wasn't using Xrefs anyway. But it would be quite simple to add it just after the (setq file .....) line.