Jump to content

List the value of an attribute in a serie of same blocks


itacad

Recommended Posts

Hello, i have to problem to read the value of an attribute in a group of same block.
I don't want to use extraction data, I simple need to read (and possibly to copy) in a window which in my case often correspond to a numerical succession.
you know a "lisp that list"?

In my example i need to read:

1 2 4 5 6 7 9 11 12

 

Thank you in advance

example for list attributes value.dwg

Link to comment
Share on other sites

This will display to the command prompt like this.

(1 2 4 5 6 7 9 11 12)

 

You can then simply highlight and copy it from there.

 

;;----------------------------------------------------------------------------;;
;; LIST ATTRIBUTE OF BLOCK
(defun C:foo (/ ss ent blk atts x lst)
  (if (setq ss (ssget "X" '((0 . "INSERT") (66 . 1) (2 . "TAG_BUS_QTA") (410 . "Model"))))
    (foreach ent (vl-remove-if 'listp (mapcar 'cadr (ssnamex SS)))
      (setq blk (vlax-ename->vla-object ent)
            atts (vlax-safearray->list (vlax-variant-value (vla-getattributes blk)))
      )
      (foreach x atts
        (if (= (vla-get-tagstring x) "QTA") 
          (setq lst (cons (atoi (vla-get-textstring x)) lst))
        )
      )
    )  
  )
  (setq lst (vl-sort lst '<))
)

 

 

Edited by mhupp
Link to comment
Share on other sites

8 hours ago, mhupp said:

You can then simply highlight and copy it from there.

 

and there was a thread recently copying text to clipboard if you want to copy straight to clipboard as well (my first comment here, 3rd line in the code with a couple of easy changes. https://www.cadtutor.net/forum/topic/74896-get-blockname-and-copy-in-memory/ )

  • Like 1
Link to comment
Share on other sites

Thank you mhupp, you understood the example perfectly!

I don't know how to program in lisp, but I can try, I ask you for help to transform the lisp so that I can use it in a more general way.

1) I would like to select a block and an attribute with different name and tag...I would like it to work on any block with an attribute.

2) I would like to list the result one result per row instead of all the results in succession on a single row

 

I try to modify your lisp but there are too many subjects unknown to me...😒

 

Thanks in advance for any help

LAOB prove.lsp

Link to comment
Share on other sites

1. Select a block and it will pop up a list of all attribute values that aren't blank. 

2. it will then select all blocks with that name and return the vaules of that tag if they aren't blank

it will automatically open your command prompt so its easier to read  the lines. if you don't like that just remove (textscr) at the end.

 

Their might be a better way to retrieve the tag but meshed part of @ronjonp code here with mine

 

;;----------------------------------------------------------------------------;;
;; DISPLAY ATTRIBUTE OF BLOCK
(defun C:foo (/ blk blkname attlst attvalue att tag ss ent atts lst)
  (while (setq blk (car (entsel "\nSelect Block")))
    (if (and (= "INSERT" (cdr (assoc 0 (setq x (entget blk))))) (setq blkname (cdr (assoc 2 x))))
      (progn
        (setq attlst (mapcar '(lambda (at) (list (vla-get-tagstring at) (vla-get-textstring at)))
                             (vlax-invoke (vlax-ename->vla-object blk) 'getattributes)
                     )
        )
        (setq attvalue (mapcar '(lambda (at) (cadr at)) attlst))
        (setq attvalue (vl-remove "" attvalue))
        (setq att (AT:ListSelect (strcat "Attribues in " blkname) "Pick A Attribue" 30 60 "false" attvalue))
        (setq tag (car (nth (vl-position (car att) (mapcar 'cadr attlst)) attlst)))
        (if (setq ss (ssget "X" (list '(0 . "INSERT") (cons 2 blkname) '(410 . "Model"))))
          (foreach ent (vl-remove-if 'listp (mapcar 'cadr (ssnamex SS)))
            (setq blk (vlax-ename->vla-object ent)
                  atts (vlax-safearray->list (vlax-variant-value (vla-getattributes blk)))
            )
            (foreach x atts
              (if (= (vla-get-tagstring x) tag)
                (setq lst (cons (vla-get-textstring x) lst))
              )
            )
          )
        )
        (setq lst (vl-remove "" lst))
        (setq lst (vl-sort lst '<))
        (prompt (strcat "\n" (itoa (length lst)) " Attribues Found"))
        (foreach x lst
          (print x)
        )
        (textscr)
      )
      (prompt "\nNot a Block")
    )
    (setq lst nil)    
  )
  (princ)
)
;;----------------------------------------------------------------------------;;
;; List Select Dialog (Temp DCL list box selection, based on provided list)
;; (AT:ListSelect "Title" "Lable" ## ## "ture/false" lst)
;; title - list box title
;; label - label for list box
;; height - height of box
;; width - width of box
;; multi - selection method ["true": multiple, "false": single]
;; lst - list of strings to place in list box
;; Alan J. Thompson, 09.23.08 / 05.17.10 (rewrite)
(defun AT:ListSelect (title label height width multi lst / fn fo d f)
  (setq fo (open (setq fn (vl-filename-mktemp "" "" ".dcl")) "w"))
  (write-line (strcat "list_select : dialog { label = \"" title "\"; spacer;") fo)
  (write-line (strcat ": list_box { label = \"" label "\";" "key = \"lst\";") fo)
  (write-line (strcat "allow_accept = true; height = " (vl-princ-to-string height) ";") fo)
  (write-line (strcat "width = " (vl-princ-to-string width) ";") fo)
  (write-line (strcat "multiple_select = " multi "; } spacer; ok_cancel; }") fo)
  (close fo)
  (new_dialog "list_select" (setq d (load_dialog fn)))
  (start_list "lst")
  (mapcar (function add_list) lst)
  (end_list)
  (setq item (set_tile "lst" "0"))
  (action_tile "lst" "(setq item $value)")
  (setq f (start_dialog))
  (unload_dialog d)
  (vl-file-delete fn)
  (if (= f 1)
    ((lambda (s / i s l)
       (while (setq i (vl-string-search " " s))
         (setq l (cons (nth (atoi (substr s 1 i)) lst) l))
         (setq s (substr s (+ 2 i)))
       )
       (reverse (cons (nth (atoi s) lst) l))
     )
      item
    )
  )
)

 

--Edit--

Just realized this might not give the correct results if the block has multiple tags with the same value.  see below.

image.png.a60dd8f6439aee36d0dbc0bd166595c1.png


 

Select Block
9 Attribues Found
"6"
"BUS"
"BUS"
"BUS"
"BUS"
"BUS"
"BUS"
"BUS"
"BUS"

 

Edited by mhupp
Error Handling / repeat command with while
Link to comment
Share on other sites

hello mhupp, and in the meantime, thanks for your help.

in the meantime I have discovered the useful command of the "utout "express tools which helps me a lot.

I have prepared a more complex file to make you understand what I was looking for.

Simulating having a single lisp with which:
- I select the block that interests me
- I select the attribute that interests me in the chosen block

I have created three examples of results that I would need


in the "white" example I select the block "TAG_BUS_QTA" and the attribute "QTA", the result that should be displayed is:

1

2

4

7

11

in the "yellow" example I select the block "DB_SCH_V4_INT_MT" and the attribute "SIGLA", the result that should be displayed is:

Q1

Q2

Q3

Q5

in the "red" example I select the block "DB_TARGHETTA_ITEM_RI" and the attribute "PROG", the result that should be displayed is:

001

004

009

201

I hope I explained myself better than in previous posts

regards

 

example for list attributes value 2.dwg

Link to comment
Share on other sites

1 hour ago, itacad said:

Simulating having a single lisp with which:

- I select the block that interests me
- I select the attribute that interests me in the chosen block

I have created three examples of results that I would need

 

That's what it currently does

: FOO
Select Block
5 Attribues Found
"01" 
"02" 
"04" 
"07" 
"11" 
Select Block
4 Attribues Found
"001" 
"004" 
"009" 
"201" 
Select Block
4 Attribues Found
"Q1" 
"Q2" 
"Q3" 
"Q5" 
Select Block

 

If you want things to show up in order they have to be the same length. This is what happens when it sorts a list of items that aren't the same length. its only looking at the first character and I don't know how to fix this.

 

1

11

2

4

7

 

Edited by mhupp
Link to comment
Share on other sites

- I select the block that interests me
- I select the attribute that interests me in the chosen block

 

You only need 1 pick using nentselect you can pick the attribute this returns its properties, ie tag name or attribute value, you then use the selection point with a ssget and auto select the block again get its properties in particular block name.

Link to comment
Share on other sites

  • 2 months later...

Hello! This bruise is very powerful!

I use it daily with a lot of time savings! I hope it will be useful to others too!

I ask this: would it be possible to make it work with the pickfirst method?

In many situations it would be more convenient for me to use it on a defined group of objects.

Thank you in advance

Link to comment
Share on other sites

Glad to hear your liking it. updated to do what you want.

 

;;----------------------------------------------------------------------------;;
;; DISPLAY ATTRIBUTE OF BLOCK
(defun C:foo (/ blk blkname attlst attvalue att tag ss ent atts lst)
  (while (setq blk (ssget "_+.:E:S" '((0 . "INSERT") (66 . 1))))
    (setq blkname (cdr (assoc 2 (entget (ssname blk 0)))))
    (setq attlst (mapcar '(lambda (at) (list (vla-get-tagstring at) (vla-get-textstring at)))
                         (vlax-invoke (vlax-ename->vla-object (ssname blk 0)) 'getattributes)
                 )
    )
    (setq attvalue (mapcar '(lambda (at) (cadr at)) attlst))
    (setq attvalue (vl-remove "" attvalue))
    (setq att (AT:ListSelect (strcat "Attribues in " blkname) "Pick A Attribue" 10 10 "false" attvalue))
    (setq tag (car (nth (vl-position (car att) (mapcar 'cadr attlst)) attlst)))
    (if (setq ss (ssget "X" (list '(0 . "INSERT") (cons 2 blkname) '(410 . "Model"))))
      (foreach ent (vl-remove-if 'listp (mapcar 'cadr (ssnamex SS)))
        (setq blk (vlax-ename->vla-object ent)
              atts (vlax-safearray->list (vlax-variant-value (vla-getattributes blk)))
        )
        (foreach x atts
          (if (= (vla-get-tagstring x) tag)
            (setq lst (cons (vla-get-textstring x) lst))
          )
        )
      )
    )
    (setq lst (vl-remove "" lst))
    (setq lst (vl-sort lst '<))
    (prompt (strcat "\n" (itoa (length lst)) " Attribues Found"))
    (foreach x lst
      (print x)
    )
    (setq lst nil)
  )
  (textscr)
  (princ)
)
;;----------------------------------------------------------------------------;;
;; List Select Dialog (Temp DCL list box selection, based on provided list)
;; (AT:ListSelect "Title" "Lable" ## ## "ture/false" lst)
;; title - list box title
;; label - label for list box
;; height - height of box
;; width - width of box
;; multi - selection method ["true": multiple, "false": single]
;; lst - list of strings to place in list box
;; Alan J. Thompson, 09.23.08 / 05.17.10 (rewrite)
(defun AT:ListSelect (title label height width multi lst / fn fo d f)
  (setq fo (open (setq fn (vl-filename-mktemp "" "" ".dcl")) "w"))
  (write-line (strcat "list_select : dialog { label = \"" title "\"; spacer;") fo)
  (write-line (strcat ": list_box { label = \"" label "\";" "key = \"lst\";") fo)
  (write-line (strcat "allow_accept = true; height = " (vl-princ-to-string height) ";") fo)
  (write-line (strcat "width = " (vl-princ-to-string width) ";") fo)
  (write-line (strcat "multiple_select = " multi "; } spacer; ok_cancel; }") fo)
  (close fo)
  (new_dialog "list_select" (setq d (load_dialog fn)))
  (start_list "lst")
  (mapcar (function add_list) lst)
  (end_list)
  (setq item (set_tile "lst" "0"))
  (action_tile "lst" "(setq item $value)")
  (setq f (start_dialog))
  (unload_dialog d)
  (vl-file-delete fn)
  (if (= f 1)
    ((lambda (s / i s l)
       (while (setq i (vl-string-search " " s))
         (setq l (cons (nth (atoi (substr s 1 i)) lst) l))
         (setq s (substr s (+ 2 i)))
       )
       (reverse (cons (nth (atoi s) lst) l))
     )
      item
    )
  )
)

 

Link to comment
Share on other sites

Thank you very much! works perfectly with this version too!

Satisfy my curiosity...What does foo mean?

Hello!

  • Like 1
  • Funny 1
Link to comment
Share on other sites

  • 8 months later...

Hi mhupp, I'm bothering you again about this useful lisp.

Perhaps the use I made today was not foreseen in the tests I had made and I ask you if what I am about to describe to you can be considered an anomaly.

In the example that I attach there are a series of blocks with attributes, they are compiled in the same way except for one attribute.

One group has the attribute labeled "bus" filled with "DALI 10" and the other group with "DALI 11".

To get to perform a "pickfirst" selection to which to apply your lisp (which in the meantime I've renamed to LAOB) I do the following:

1) I use the powerful lisp SelBlksByAttTag (found on this forum) and I select the blocks with "DALI 10".

2) I run the lisp LAOB

3) select the fourth proposed item from the drop-down menu (which corresponds to the attribute labeled "ID")

4) lisp returns the list of ID values, but also including the blocks that have the "BUS" label compiled with "DALI 11", in this way I can't have the sequence of ID I want to check available

 

Is it possible to change the lisp to actually apply only to the group of selected objects before launching?

I also ask you if it is possible to modify the lisp drop-down menu so that it proposes the attribute label and not the content it proposes (this aspect would be useful but not important)

 

Thank you in advance

LAOB test pickfirst selection.dwg LAOB.lsp SelBlksByAttTag.lsp

Link to comment
Share on other sites

Updated the lisp to streamline the process. You no longer have to select a text from a list just select it with your mouse and it will spit out how many block it found and the value. and error checking to see if it was a attribute you selected.

Example

 

 

 

LAOB-2.0.lsp

Edited by mhupp
  • Like 1
Link to comment
Share on other sites

Sorry but I probably didn't explain myself well, maybe due to my poor English.

The lisp was fine as it was before because it allowed me to read all the values of the selected attribute (ID) thus being able to check the sequence, with this update this functionality is gone.

Basically I want:

- Select a group of blocks (operation independent of LOAB)

- Proceed to launch the lisp LOAB (pickfirst) which must perform the check only on the selected group of blocks (in my example I preselected all blocks with the "BUS" attribute filled in with "DALI 10")

- select from the LOAB lisp dialog the attribute to check (in my example the ID attribute)

- read the sequence that lisp displays in the command line:

"20" "21" "22" "23" "24" "25" "26" "27" "28" "29" "30" "31" "32" "33" "34" "35" "36" "36" "37" "38" "39" "40" "41" "42" "43" "44" "45" "46" "47" "48" "49" "50" "51" "52" "53" "54" "55"

(in my example id 36 is duplicate and i need to fix it)

The problem I encountered is that the lisp of the previous revision does not only control the pre-selected group (DALI 10) but also integrates the other non-pre-selected blocks into the control, this means that I can't check only the IDs of the DALI 10.

 

Thank you for your patience and for your work

Link to comment
Share on other sites

A few things. it does what the old lisp did but better/faster. using getpropertyvalue and setpropertyvalue so you don't have to test each attribute of each block.

these commands are used in autocad but they don't work with my BricsCAD. So I can't really test the lisp.

 

 But what it should do is the following.

 

:LAOB

Select Block Attribute: *pick ID

*list all attributes

-----------------------------

37 Attributes found

Process Results? Yes/<No>: Yes

Select Block by value: *input 36

2 Blocks Found 

Change Values? Yes/<No>: Yes

*Zoom to first one

Input [36]: *input 56

Attribute updated to "56"

*Zoom to Next

Input [36]: *enter

*zoom back out.

Select Block Attribute:

 

check last post for updated lisp.

 

Link to comment
Share on other sites

Thanks, I tried but it gives me an error

 

Comando: LAOB
Select Block Attribute: ; errore: tipo di argomento errato: (or stringp symbolp): nil

 

But re-reading your last post. the logic you are applying is not what I need, if the lisp works as you describe, it no longer allows me to control the numerical sequence of the IDs because I should manually enter "36" even though I don't know in advance that it is a repeated value as I don't have the sequence that was shown in the command line with the first version.

lisp was fine as it was, the only drawback it had was that it couldn't actually be applied to just the actually selected blocks before being executed.

 

However, I don't want to waste your time, I will use the previous version and copy only the blocks to be checked onto an empty drawing and from there I will use the lisp, making sure that the check takes place only on those blocks

 

Link to comment
Share on other sites

14 hours ago, itacad said:

if the lisp works as you describe, it no longer allows me to control the numerical sequence of the IDs

 

Where i posted "*list all attributes" it still outputs the id's the the command line

 

20

21

22

23

24

...

 

Just didn't want to type them all out. and i didn't really like what it was doing (too much spam) so I went back and made the code the old way so I could test things. and made a few updates.

 

Now when you select an attribute it will check for duplicates. if it finds any it will list them out and then ask you if you want to process the results if you do it will ask for a search string

this is case sensitive. so if i typed gr.8 it wouldn't find anything.

 

: LAOB
Select Block Attribute:
"GR.10" Found 2 Time(s)
"GR.11" Found 16 Time(s)
"GR.12" Found 2 Time(s)
...
Process Results? Yes/<No>: y
Value to Search: GR.8

 

it will then zoom to each block that matches GR.8 and ask for an input. if you don't want to change anything just hit enter and it will go to the next block. if you do typing it in there will update the your looking at.

 

Change [GR.8]:test
Attribute updated to "test"

 

After all blocks are cycled thought it will zoom back out and ask for another selection to start the process over again.

 

two things. you will only see duplicated items now or a unique list (I could change this back if you want)

No Duplicate Values Found list Results? Yes/<No>:y
"20"
"21"
"22"
...

 

if something is mistyped it won't be found as a duplicate. like "GR.8" "gR.8" "G R.8" are all seen as different.

 

When it ask yes or no  "<no>" is default so you can hit enter or right click to skip.

 

See updated code above.

Link to comment
Share on other sites

Thanks but it still gives me an error

LAOB
Select Block Attribute: ; errore: funzione errata: #<SUBR @0000019e286eaa70 -lambda->

I specify one thing: the block I used is an example, I may have to check others with different attributes

Greetings

Link to comment
Share on other sites

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.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...