Visual LISP, AutoLISP and General Customization
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Get value of an attribute irregardless of block name

19 REPLIES 19
SOLVED
Reply
Message 1 of 20
Anonymous
3060 Views, 19 Replies

Get value of an attribute irregardless of block name

I saw this awesome post: http://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/get-the-value-of-an-attribute/td-p/32...

That shows how to get a value of an attribute provided a block and a tag name...

 

I used this code and was able to get an attribute value from the "SCALE" one question I do have.  In the code the author passes both the name of the block (first parameter) and the name of the tag / attribute name (in my case SCALE).  So I called it like so:

 

(defun ShowVal (blkn Tag / aDoc ss tvl)
(vl-load-com)
(setq aDoc (vla-get-ActiveDocument (vlax-get-acad-object)))
(cond
((and
(ssget "_X" (list '(0 . "INSERT") '(66 . 1) (cons 2 (strcat blkn ",`*U*"))))
(vlax-for bls (setq ss (vla-get-ActiveSelectionSet aDoc))
(if (and ( eq (strcase (vla-get-effectivename bls))
(strcase blkn))
(setq tvl (assoc (strcase Tag) (mapcar
'(lambda (j)
(list
(vla-get-tagstring j)
(vla-get-textstring j)))
(vlax-invoke bls 'GetAttributes))))
)
(print (cadr tvl))
)
)
(vla-delete ss)
)
)
)
(princ)
)

 

(SHOWVAL "Block1_A0" "Scale")

 

My question is can anyone for that matter modify this code to work on ANY block, meaning modify the function call to ignore the block and just look for the tag name scale, like so:

 

(SHOWVAL "Scale")

 

So it should maybe ignore the block name (I dont know enough autocad so maybe ignore means loop through all blocks).  I simply need to get the attribute value irregardless of the block name.

 

Thanks

19 REPLIES 19
Message 2 of 20
Kent1Cooper
in reply to: Anonymous


@Anonymous wrote:

....  In the code the author passes both the name of the block (first parameter) and the name of the tag / attribute name (in my case SCALE).  .... 

My question is can anyone ... modify this code to work on ANY block, meaning modify the function call to ignore the block and just look for the tag name scale, like so:

 

(SHOWVAL "Scale")

 

So it should maybe ignore the block name ....


Without trying it out, but quickly....

 

Try changing this line:

 

(defun ShowVal (blkn Tag / aDoc ss tvl)

 

to this [removing the Block name from the required input arguments]:

 

(defun ShowVal (Tag / aDoc ss tvl)

 

and this line:

 

(ssget "_X" (list '(0 . "INSERT") '(66 . 1) (cons 2 (strcat blkn ",`*U*"))))

 

to this [removing the Block name from the filtering characteristics]:

 

(ssget "_X" (list '(0 . "INSERT") '(66 . 1)))

Kent Cooper, AIA
Message 3 of 20
Anonymous
in reply to: Kent1Cooper

Hi Kent,

 

I tried with this:

 

(defun ShowVal (Tag / aDoc ss tvl)
(vl-load-com)
(setq aDoc (vla-get-ActiveDocument (vlax-get-acad-object)))
(cond
((and
(ssget "_X" (list '(0 . "INSERT") '(66 . 1)))
(vlax-for bls (setq ss (vla-get-ActiveSelectionSet aDoc))
(if (and ( eq (strcase (vla-get-effectivename bls))
(strcase blkn))
(setq tvl (assoc (strcase Tag) (mapcar
'(lambda (j)
(list
(vla-get-tagstring j)
(vla-get-textstring j)))
(vlax-invoke bls 'GetAttributes))))
)
(print (cadr tvl))
)
)
(vla-delete ss)
)
)
)
(princ)
)

 

(setvar "dimscale" (SHOWVAL "SCALE"))

 

But I get an error bad argument type: stringp nil

Message 4 of 20
Kent1Cooper
in reply to: Anonymous

[Sorry -- that's what comes of un-tested quickie suggestions....]

 

You would also need to take out the part that checks for the Block's effective name, since the name doesn't matter any more, and you're not supplying one [that's where the error is coming from].  Try removing this much:

 

          (eq (strcase (vla-get-effectivename bls)) (strcase blkn))

 

I think the surroundings could be simplified somewhat, because that's one of it looks like two checks in an (and) function that could be eliminated if there's only one thing left to check for, but start by seeing whether taking that one check out gets it to work.

Kent Cooper, AIA
Message 5 of 20
Anonymous
in reply to: Kent1Cooper

i tried removing just that portion but than the if condition was strange, then I tried this:

 

(defun ShowVal (Tag / aDoc ss tvl)
(vl-load-com)
(setq aDoc (vla-get-ActiveDocument (vlax-get-acad-object)))
(cond
((and
(ssget "_X" (list '(0 . "INSERT") '(66 . 1)))
(vlax-for bls (setq ss (vla-get-ActiveSelectionSet aDoc))
(setq tvl (assoc (strcase Tag) (mapcar
'(lambda (j)
(list
(vla-get-tagstring j)
(vla-get-textstring j)))
(vlax-invoke bls 'GetAttributes))))
)
(print (cadr tvl))
)
)
(vla-delete ss)
)
)
)
(princ)
)

 

(setvar "dimscale" (SHOWVAL "SCALE"))

 

And its even worse now!  Man I dont know how people program lisp, this is the ugliest language I've ever seen.  😞

Message 6 of 20
Moshe-A
in reply to: Anonymous

Hi,

 

"I dont know how people program lisp, this is the ugliest language I've ever seen."

 

You want to understand a language that you never took the time to learn? that's impossible!

 

the function you bring here select all the blocks in the current drawing and loop them to show an attribute value

have you notice the function name?  (showval)

 

what you want is to get One value/scale  from one block but your function does not do that,

it only shows the values on autocad text screen it doesn't return any scale value.

 

 

here is another simple version of doing it and i hope you now would like it  Smiley Very Happy

 

 

(defun c:test (/ get_attrib_value ; local function
	         ss i ename attVal)
  
 (defun get_attrib_value (ename attTag / subent sube flag attVal)
  (setq subent (entnext ename) sube (entget subent))
   
  (while (and (not flag)
	      (/= (cdr (assoc '0 sube)) "SEQEND")
	 )
   (if (eq (strcase (cdr (assoc '2 sube))) (strcase attTag))
    (setq attVal (cdr (assoc '1 sube)) flag t)
   )

   (setq subent (entnext subent) sube (entget subent))
  ); while

  attVal
 ); get_attrib_value


 ; pause to select attribute blocks
 (if (setq ss (ssget (list '(0 . "insert") '(66 . 1))))
  (progn
   (setq i -1)
   (repeat (sslength ss)
    (setq i (1+ i) ename (ssname ss i))
    (setq attVal (get_attrib_value ename "scale"))

    (setvar "dimscale" (atof attval))
   ); repeat
  ); progn
 ); if

 
 (princ)
)

 

save this to a lisp file and load it in your drawing were your block with scale attribute exist

invoke TEST command and select the block and the DIMSCALE will get the right value.

 

if you select more then 1 block with different scale values then DIMSCALE will have only the last block in the loop.

 

cheers

Moshe

 

 

Message 7 of 20
Kent1Cooper
in reply to: Anonymous

As a start, I did some indenting and such, and added some comments....

 

(defun ShowVal (Tag / aDoc ss tvl)
  (vl-load-com)
  (setq aDoc (vla-get-ActiveDocument (vlax-get-acad-object)))
  (cond
    ( ; open first [and in this case, only] condition to check for
      (and
        (ssget "_X" (list '(0 . "INSERT") '(66 . 1))); User selected at least one Block with Attributes
        (vlax-for bls (setq ss (vla-get-ActiveSelectionSet aDoc))
          ; for each Block in selection-set-as-VLA-object
          (setq tvl
            (assoc
              (strcase Tag)
              (mapcar
                '(lambda (j)
                  (list
                    (vla-get-tagstring j)
                    (vla-get-textstring j)
                  ); list
                ); lambda
                (vlax-invoke bls 'GetAttributes); list of all Attributes in Block, as VLA objects
              ); mapcar
                ;; (mapcar) returns list of sublists, each sublist being a list of Tag name and value
            ); assoc
              ;; (assoc) returns the sublist with the right Tag name
          ); setq -- put list of right Tag name with its value into 'tvl' variable
        ); vlax-for
      ); and ;;;;; moved this up here, so if above is satisfied, it will do line below:
        (print (cadr tvl)); the value associated with that Tag name
;      ); and ;;;;; was in the wrong place [I think]
    ); end (and)-test condition
;    (vla-delete ss)
      ;; if this was meant to be the fall-back condition, it's not formatted right
      ;; [should have two parentheses at each end], but in any case, do you
      ;; want to delete anything?
  ); cond
;;;;; ); extraneous
;;;;; ); extraneous
  (princ)
); defun

 

That at least returns a value, for me.  But it returns only one if there are more than one Block with the right Tag name.  Is it your intent to show all such values in multiple Blocks?

Kent Cooper, AIA
Message 8 of 20
Kent1Cooper
in reply to: Anonymous


@Anonymous wrote:

.... 

(setvar "dimscale" (SHOWVAL "SCALE"))

....


Oh, and another thing:  I hadn't noticed that bit -- if you're going to use the result to set the DIMSCALE System Variable [which would mean the returns-only-one-value issue in my previous Reply won't matter], you're going to need to convert it, because the returned Attribute value will be a text string.  Something like:

 

(setvar 'dimscale (atof (showval "SCALE")))

 

[If you only use integer DIMSCALE values, (atoi) would be enough.]

 

But that also depends on the Attribute value being written in the right kind of text string.  If, for example, it's something like "1:50", that won't work.

Kent Cooper, AIA
Message 9 of 20
Anonymous
in reply to: Kent1Cooper

Err ken you are spot on the current value comes in the form of 1:5.


Do you have any way of doing it given a value like that?

 

Thanks so much you are awesome!

Message 10 of 20
Kent1Cooper
in reply to: Anonymous


@Anonymous wrote:

Err ken you are spot on the current value comes in the form of 1:5.


Do you have any way of doing it given a value like that?

 

Thanks so much you are awesome!


If they always start with a 1 and a colon, and the rest is the DIMSCALE number you want:

 

(setvar 'dimscale (atoi (substr (showval "SCALE") 3)))

 

EDIT:  Use (atof) if the scales are ever non-integer values, such as 2.5 or something.

Kent Cooper, AIA
Message 11 of 20
Anonymous
in reply to: Kent1Cooper

Err yet again I tried with this:

 

(defun ShowVal (Tag / aDoc ss tvl)
(vl-load-com)
(setq aDoc (vla-get-ActiveDocument (vlax-get-acad-object)))
(cond
( ; open first [and in this case, only] condition to check for
(and
(ssget "_X" (list '(0 . "INSERT") '(66 . 1))); User selected at least one Block with Attributes
(vlax-for bls (setq ss (vla-get-ActiveSelectionSet aDoc))
; for each Block in selection-set-as-VLA-object
(setq tvl
(assoc
(strcase Tag)
(mapcar
'(lambda (j)
(list
(vla-get-tagstring j)
(vla-get-textstring j)
); list
); lambda
(vlax-invoke bls 'GetAttributes); list of all Attributes in Block, as VLA objects
); mapcar
;; (mapcar) returns list of sublists, each sublist being a list of Tag name and value
); assoc
;; (assoc) returns the sublist with the right Tag name
); setq -- put list of right Tag name with its value into 'tvl' variable
); vlax-for
); and ;;;;; moved this up here, so if above is satisfied, it will do line below:
(print (cadr tvl)); the value associated with that Tag name
; ); and ;;;;; was in the wrong place [I think]
); end (and)-test condition
; (vla-delete ss)
;; if this was meant to be the fall-back condition, it's not formatted right
;; [should have two parentheses at each end], but in any case, do you
;; want to delete anything?
); cond
(princ)
); defun

(SHOWVAL "Scale")

 

And it doesnt return any value...if I use the old code that takes in both a block and a tag than it shows the correct value so I still am not getting the scale with this code :(....

 

Message 12 of 20
Kent1Cooper
in reply to: Anonymous


@Anonymous wrote:

Err yet again I tried with this:

.... 

And it doesnt return any value...if I use the old code that takes in both a block and a tag than it shows the correct value so I still am not getting the scale with this code :(....

 


It does for me.  [I even copied/pasted your latest, in case any little thing got altered, but that works here.]  I don't have any other ideas....

Kent Cooper, AIA
Message 13 of 20
Anonymous
in reply to: Kent1Cooper

Hmph I don't know why.

If I try to load the lisp file all it says is:

 

Command: (Load c:/users/myname/desktop/MyLispFile.lsp")

 

With nothing else...same thing If I drag the lisp file onto the drawing...no output.  The code I have is this:

 

(defun ShowVal (Tag / aDoc ss tvl)
(vl-load-com)
(setq aDoc (vla-get-ActiveDocument (vlax-get-acad-object)))
(cond
( ; open first [and in this case, only] condition to check for
(and
(ssget "_X" (list '(0 . "INSERT") '(66 . 1))); User selected at least one Block with Attributes
(vlax-for bls (setq ss (vla-get-ActiveSelectionSet aDoc))
; for each Block in selection-set-as-VLA-object
(setq tvl
(assoc
(strcase Tag)
(mapcar
'(lambda (j)
(list
(vla-get-tagstring j)
(vla-get-textstring j)
); list
); lambda
(vlax-invoke bls 'GetAttributes); list of all Attributes in Block, as VLA objects
); mapcar
;; (mapcar) returns list of sublists, each sublist being a list of Tag name and value
); assoc
;; (assoc) returns the sublist with the right Tag name
); setq -- put list of right Tag name with its value into 'tvl' variable
); vlax-for
); and ;;;;; moved this up here, so if above is satisfied, it will do line below:
(print (cadr tvl)); the value associated with that Tag name
; ); and ;;;;; was in the wrong place [I think]
); end (and)-test condition
; (vla-delete ss)
;; if this was meant to be the fall-back condition, it's not formatted right
;; [should have two parentheses at each end], but in any case, do you
;; want to delete anything?
); cond
(princ)
); defun

(SHOWVAL "Scale")

Message 14 of 20
hmsilva
in reply to: Anonymous

Hi joqarmaza,
perhaps easier to understand this AutoLISP code

 

(defun tagval (tag / ent hnd i lst ss)
  (if (setq ss (ssget "_X" (list '(0 . "INSERT") '(66 . 1) (cons 410 (getvar 'CTAB)))))
    (repeat (setq i (sslength ss))
      (setq hnd (ssname ss (setq i (1- i))))
      (while (and
               (setq hnd (entnext hnd))
               (setq ent (entget hnd))
               (= (cdr (assoc 0 ent)) "ATTRIB")
             )
        (if (= (strcase tag) (strcase (cdr (assoc 2 ent))))
          (setq lst (cons (cdr (assoc 1 ent)) lst))
        )
      )
    )
  )
  (if lst
    (car lst)
  )
)

 

as your goal is to set 'dimscale', and as you have stated before

'the current value comes in the form of 1:5'

you can try something like this

 

(if (and (setq val (tagval "Scale"))
         (setq pos (vl-string-position (ascii ":") val))
    )
  (setvar 'dimscale (atof (substr (showval "SCALE") (+ 2 pos))))
  (princ "\n\"Scale\" TAG was not found, or not in the \"#:##\" form!")
)

 

Hope that helps

Henrique

 

EESignature

Message 15 of 20
cbenner
in reply to: hmsilva

@hmsilva

 

Resurrecting this old thread, as a possible help to my latest attempt...  please see my last post in >>this thread<<, dated 3/27/2018.

 

Is there anything similar to this code you offered several years ago that might help me in my quest?

Message 16 of 20
hmsilva
in reply to: cbenner

Hi Chris,

if your last-num is an integer, perhaps something like this...

 

(defun tagnum (tag / ent hnd i lst lst1 num ss)
    (if (setq ss (ssget "_X" (list '(0 . "INSERT") '(66 . 1) (cons 410 (getvar 'CTAB)))))
        (repeat (setq i (sslength ss))
            (setq hnd (ssname ss (setq i (1- i))))
            (while (and
                       (setq hnd (entnext hnd))
                       (setq ent (entget hnd))
                       (= (cdr (assoc 0 ent)) "ATTRIB")
                   )
                (if (= (strcase tag) (strcase (cdr (assoc 2 ent))))
                    (setq lst (cons (cdr (assoc 1 ent)) lst))
                )
            )
        )
        (setq num 0)
    )
    (if lst
        (progn
            (foreach str lst
                (if (/= (setq res (vl-list->string (vl-remove-if-not '(lambda (x) (<= 48 x 57)) (vl-string->list str))))
                        ""
                    )
                    (setq lst1 (cons (atoi res) lst1))
                )
            )
            (if lst
                (setq num (apply 'max lst1))
                (setq num 0)
            )
        )
        (setq num 0)
    )
    num
)

;usage 
; (setq last-num (tagnum "Tag"))

 

Untested....

 

Hope this helps,
Henrique

EESignature

Message 17 of 20
cbenner
in reply to: hmsilva

@hmsilva

 

Thank you for responding and sharing your talent.

 

Does this code search for a selected block, or does it search for a tag, independent of block name?  How do I tell it what tag string to search for?

 

When I set last_num using this, it returns "0".

Message 18 of 20
hmsilva
in reply to: cbenner


@cbenner wrote:

@hmsilva

 

Thank you for responding and sharing your talent.

 

Does this code search for a selected block, or does it search for a tag, independent of block name?  How do I tell it what tag string to search for?

 

When I set last_num using this, it returns "0".


The code will search for a tag, independent of block name.

 

(setq last-num (tagnum "Tag"))

 

"Tag" is the tag name.... just change it to the correct tag name.

 

Henrique

EESignature

Message 19 of 20
cbenner
in reply to: hmsilva

@hmsilva

 

Thank you!  I didn't catch that.  This works great.  Now I can add this to my overall routine, and go from there.

 

If I run into further issues with the overall routine, I'll start a new thread.  For now I'm going to mark this accepted.  Thanks again!

Message 20 of 20
hmsilva
in reply to: cbenner


@cbenner wrote:

...

 

Thank you!  I didn't catch that.  This works great.  Now I can add this to my overall routine, and go from there.

 

If I run into further issues with the overall routine, I'll start a new thread.  For now I'm going to mark this accepted.  Thanks again!


You're welcome, Chris!
Glad I could help

Henrique

EESignature

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report

”Boost