Author Topic: Attribute replacer  (Read 3482 times)

0 Members and 1 Guest are viewing this topic.

Shade

  • Guest
Attribute replacer
« on: November 10, 2005, 01:09:39 PM »
I am trying to write a attribute value replacer, in visual lisp. The following is what I have come up with.

Code: [Select]
(Defun ATTREPLACE (ENM ATT TXT)
  (setq OBJ (VLAX-ENAME->VLA-OBJECT ENM)
        ATT (VLA-GETATTRIBUTES OBJ)
        VAR (VLAX-VARIANT-VALUE ATT)
        CNT (vlax-safearray-get-dim VAR)     
  );
  (while (>= CNT 0)
   (setq ARG (VLAX-SAFEARRAY-GET-ELEMENT VAR CNT)
   CNT (- CNT 1)
   CHK (vlax-get-property ARG "TagString")
   )
   (if (= CHK ATT)
       (setq CNT 0
     VAL (vlax-put-property ARG "TextString" TXT)
       )
   );if
  );while 
);#ATTREPLACE

The problemI am having, is I know a attribute exist in the block I pass to the lisp, but for some reason the lisp does not change the existing value to the new value.
The only reason I can figure out why is that the safety arrays dimension is 1 insetad of 6, which is the number of attributes I have in the block.

Why does (vlax-safearray-get-dim VAR) return 1 when there are 6 attributes in the block?
  :realmad:

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Attribute replacer
« Reply #1 on: November 10, 2005, 02:01:45 PM »
To get a list of attributes within a block, it is easier to use (vlax-invoke Obj 'GetAttributes).

Tim
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

whdjr

  • Guest
Re: Attribute replacer
« Reply #2 on: November 10, 2005, 02:20:55 PM »
Short and Sweet!

I like it T. :-)

Jeff_M

  • King Gator
  • Posts: 4096
  • C3D user & customizer
Re: Attribute replacer
« Reply #3 on: November 10, 2005, 02:46:17 PM »
Shade, while Tim's solution is far easier to work with, I'll attempt to answer your question.
A single dimension array is one with 1 column and multiple rows for the data. So the call to (vlax-safearray-get-dim VAR) returns 1 because there is just 1 column. To access what you thought you were you need to use the (vlax-safearray-get-l-bound VAR 1)...this is the lower index starting number of dimension(column) 1...and (vlax-safearray-get-u-bound VAR 1)...this is the upper value of dimension(column) 1 so if the lbound is 0 and the ubound is 5 you have 6 elements in that array's dimension.

And that is why using Tim's method is easier :)

Jeff_M

  • King Gator
  • Posts: 4096
  • C3D user & customizer
Re: Attribute replacer
« Reply #4 on: November 10, 2005, 02:52:14 PM »
Written on the fly, not tested but should work....this does what you are looking for
Code: [Select]
(defun attreplace (enm att txt / atts )
  (setq obj (vlax-ename->vla-object enm)
        atts (vlax-invoke obj 'getattributes)
  );
  (foreach x atts
   (if (eq (vlax-get-property x "tagstring") att)
     (vlax-put-property x "textstring" txt)
     );if
  );foreach
);#attreplace

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Attribute replacer
« Reply #5 on: November 10, 2005, 03:00:29 PM »
Thanks for the explaination Jeff.  I always love learning new things, and understanding why I do things the way I do.  I think I got the idea of using (vlax-get... and (vlax-invoke.. off some people at the AutoCad customization forums, and they seem to work better, when I remember to use the. :ugly:

Tim
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

whdjr

  • Guest
Re: Attribute replacer
« Reply #6 on: November 10, 2005, 03:11:22 PM »
Written on the fly, not tested but should work....this does what you are looking for
Code: [Select]
(defun attreplace (enm att txt / atts )
  (setq obj (vlax-ename->vla-object enm)
        atts (vlax-invoke obj 'getattributes)
  );
  (foreach x atts
   (if (eq (vlax-get-property x "tagstring") att)
     (vlax-put-property x "textstring" txt)
     );if
  );foreach
);#attreplace

I haven't tested it but shouldn't 'foreach' be 'vlax-for' - since you're working with objects?

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Attribute replacer
« Reply #7 on: November 10, 2005, 03:27:35 PM »
I haven't tested it but shouldn't 'foreach' be 'vlax-for' - since you're working with objects?
Nope.  When you use (vlax-invoke Obj 'GetAttributes) it returns a list of all the attribute objects.  You use vlax-for for collections, ie. layers, blocks and text styles.

Tim
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

Jeff_M

  • King Gator
  • Posts: 4096
  • C3D user & customizer
Re: Attribute replacer
« Reply #8 on: November 10, 2005, 03:33:14 PM »
Will, a quick example (and this is why I like this method instead of the other....)
Quote
(setq tmp (vlax-ename->vla-object (car (entsel))))
Select object: #<VLA-OBJECT IAcadBlockReference2 17005e44>
Command: (setq atts (vlax-invoke tmp 'getattributes))
(#<VLA-OBJECT IAcadAttributeReference2 18878d04> #<VLA-OBJECT
IAcadAttributeReference2 18878cb4> #<VLA-OBJECT IAcadAttributeReference2
1887fe34>)
Command: (type atts)
LIST

whdjr

  • Guest
Re: Attribute replacer
« Reply #9 on: November 10, 2005, 03:34:08 PM »
ok I see. :oops:

Andrea

  • Water Moccasin
  • Posts: 2372
Re: Attribute replacer
« Reply #10 on: November 14, 2005, 08:15:17 PM »
Code: [Select]
(defun attreplace (enm att txt / atts )
  (setq obj (vlax-ename->vla-object enm)
        atts (vlax-invoke obj 'getattributes)
  );
  (foreach x atts
   (if (eq (vlax-get-property x "tagstring") att)
     (vlax-put-property x "textstring" txt)
     );if
  );foreach
);#attreplace

Hey guys...i'm trying to understand the code..
but something not working when making tests..

maybe...
(if (eq (vlax-get-property x "tagstring") atts)

also...I got an error in this line..

Code: [Select]
(vlax-put-property x "textstring" txt)  what exacly the txt supposed to do ?

I have modified the code like this..(for testing)


Code: [Select]
(defun c:attr (enm att txt / atts )
  (setq enm (entget (car (entsel))))
  (setq obj (vlax-ename->vla-object (cdar enm)))
   (setq atts (vlax-invoke obj 'getattributes))
 
  (foreach x atts     
   (if (eq (vlax-get-property (car atts) "tagstring") atts)
     (vlax-put-property obj "textstring" txt)
     );if
  );foreach
);#attreplace


but..don't know realy.. :|
Keep smile...

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Attribute replacer
« Reply #11 on: November 14, 2005, 08:29:56 PM »
What is your error message ?

kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Attribute replacer
« Reply #12 on: November 14, 2005, 08:30:54 PM »
.. and how are you calling this :-   c:attr
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Jeff_M

  • King Gator
  • Posts: 4096
  • C3D user & customizer
Re: Attribute replacer
« Reply #13 on: November 15, 2005, 12:44:25 AM »
Andrea,
That function was designed to accept 3 arguments:
enm = the ENAME of the block containing the attribute to edit
att = the TAG of the attribute to edit
txt = the TEXT value to place into the attribute

You did not need to change the line from att to atts.

Try something like this:
(setq blk (car (entsel "\nSelect block: "))
         att (strcase (getstring "\nName of attribute TAG: "))
         txt (getstring "\nNew value for attribute: ")
       )
(attreplace blk att txt)

whdjr

  • Guest
Re: Attribute replacer
« Reply #14 on: November 15, 2005, 09:51:33 AM »
Shade,

You might find this link useful.