Author Topic: List manipulation (dcl list_box)  (Read 4588 times)

0 Members and 1 Guest are viewing this topic.

kruuger

  • Swamp Rat
  • Posts: 637
List manipulation (dcl list_box)
« on: January 29, 2013, 03:15:53 PM »
hello swamp'ers

let say i open the file and reads all blocks from each layout.
i create a list LST

Code: [Select]
(setq LST
  (list 1-block-items
    (cons 1 FileName)
    (cons 2 LayoutName)
    (cons 3 BlockName)
    (more cons if needed)
    (list
      (cons "VIEW" "Elevation")
      (cons "SHEET" "Layout1")
      ...
      all attributes from BlockName
    )
  )
  (list 2-block-items
    (cons 1 FileName)
    (cons 2 LayoutName)
    (cons 3 BlockName)
    (more cons if needed)
    (list
      (cons "VIEW" "Elevation")
      (cons "SHEET" "Layout1")
      ...
      all attributes from BlockName
    )
  )
  (list 3-block-items
    (cons 1 FileName)
    (cons 2 LayoutName)
    (cons 3 BlockName)
    (more cons if needed)
    (list
      (cons "VIEW" "Elevation")
      (cons "SHEET" "Layout1")
      ...
      all attributes from BlockName
    )
  )
  ...
)

at dcl dialog i have five list_box which will be filled with info:
- drawing files
- layouts for selected drawing
- blocks for layout
- tags for block
- and values for tags

all is fine to this point. i filter my LST and display appropriate info where required

now, when i select item on last list (Attribute value) i want to know where this item is on the LST, on which position.

what is the best way to work with that kind if data ? work with one list LST ? make separate lists for file name, layouts, bloks ..etc

thanks for any hints
kruuger

Lee Mac

  • Seagull
  • Posts: 12926
  • London, England
Re: List manipulation (dcl list_box)
« Reply #1 on: January 29, 2013, 06:08:37 PM »
I would use a nested list structure:

Code: [Select]
(
    (   "D:\\1-01.dwg"
        (   "Model"
            (   "ROOM TAG"
                (   "AREA_NAME_1" "123" "AREA"   )
                (   "AREA_NAME_2" "123" "AREA"   )
                ...
                (   <Tag Name N> <Value1> ... <ValueN>   )
            )
            ...
            (   <Block Name N>
                (   <Tag Name 1> <Value1> ... <ValueN>   )
                ...
                (   <Tag Name N> <Value1> ... <ValueN>   )
            )
        )
        ...
        (   <Layout Name N>
            (   <Block Name 1>
                (   <Tag Name 1> <Value1> ... <ValueN>   )
                ...
                (   <Tag Name N> <Value1> ... <ValueN>   )
            )
            ...
            (   <Block Name N>
                (   <Tag Name 1> <Value1> ... <ValueN>   )
                ...
                (   <Tag Name N> <Value1> ... <ValueN>   )
            )
        )
    )
    ...
    (   <Drawing Name N>
        (   <Layout Name 1>
            (   <Block Name 1>
                (   <Tag Name 1> <Value1> ... <ValueN>   )
                ...
                (   <Tag Name N> <Value1> ... <ValueN>   )
            )
            ...
            (   <Block Name N>
                (   <Tag Name 1> <Value1> ... <ValueN>   )
                ...
                (   <Tag Name N> <Value1> ... <ValueN>   )
            )
        )
        ...
        (   <Layout Name N>
            (   <Block Name 1>
                (   <Tag Name 1> <Value1> ... <ValueN>   )
                ...
                (   <Tag Name N> <Value1> ... <ValueN>   )
            )
            ...
            (   <Block Name N>
                (   <Tag Name 1> <Value1> ... <ValueN>   )
                ...
                (   <Tag Name N> <Value1> ... <ValueN>   )
            )
        )
    )
)

Then assoc may be used at each level.

kruuger

  • Swamp Rat
  • Posts: 637
Re: List manipulation (dcl list_box)
« Reply #2 on: January 30, 2013, 03:54:20 AM »
...
Then assoc may be used at each level.
Lee thanks for interesting.

i don't get the idea with assoc

follow your list we can do something like this:
Code: [Select]
(setq a
    (list
        (list   "D:\\1-01.dwg"
            (list   "Model"
                (list   "ROOM TAG"))
            (list   "Layout1"
                (list   "ROOM TAG"))
            (list   "Layout2"
                (list   "ROOM TAG"))
        )
        (list   "D:\\2-01.dwg"
            (list   "Model"
                (list   "TAG"))
            (list   "Lay1"
                (list   "TAG"))
            (list   "Lay2"
                (list   "TAG"))
        )
    )
)

dwg list:
Code: [Select]
(mapcar 'car a) -> ("D:\\1-01.dwg" "D:\\2-01.dwg")dwg 1-01 layouts:
Code: [Select]
(mapcar 'car  (cdar a)) -> ("Model" "Layout1" "Layout2")
is this what you mean ?

thanks
kruuger

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: List manipulation (dcl list_box)
« Reply #3 on: January 30, 2013, 04:16:30 AM »
Probably not assoc, rather use nth since the list_box callback could then pick up the selected index of the list_box. Say the user pick's 1-01.dwg in your sample: The callback could then obtain the get_tile to obtain the selected index (note this returns a string of integer(s) - so probably need read / atoi). Then use nth with that index on your data list like so:
Code - Auto/Visual Lisp: [Select]
  1. (defun _DrawingSelected (/ idx data)
  2.   (setq idx (atoi (get_tile "Drawings")) data (nth idx a))
  3.   ;; Continue refreshing the other list_boxes, data should now contain:
  4.   ;; ("D:\\1-01.dwg"
  5.   ;;   ("Model"
  6.   ;;     ("ROOM TAG" ("AREA_NAME_1" "123" "AREA")
  7.   ;;     ("AREA_NAME_2" "123" "AREA")
  8.   ;;     ...
  9.   ;;     (<Tag Name N> <Value1> ... <ValueN>))
  10.   ;;   ...
  11.   ;;   (<Block Name N>
  12.   ;;     (<Tag Name 1> <Value1> ... <ValueN>)
  13.   ;;     ...
  14.   ;;     (<Tag Name N> <Value1> ... <ValueN>))))
  15. )
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

kruuger

  • Swamp Rat
  • Posts: 637
Re: List manipulation (dcl list_box)
« Reply #4 on: January 30, 2013, 05:15:27 AM »
Probably not assoc, rather use nth since the list_box callback could then pick up the selected index of the list_box. Say the user pick's 1-01.dwg in your sample: The callback could then obtain the get_tile to obtain the selected index (note this returns a string of integer(s) - so probably need read / atoi). Then use nth with that index on your data list like so:
Code - Auto/Visual Lisp: [Select]
  1. (defun _DrawingSelected (/ idx data)
  2.   (setq idx (atoi (get_tile "Drawings")) data (nth idx a))
  3.   ;; Continue refreshing the other list_boxes, data should now contain:
  4.   ;; ("D:\\1-01.dwg"
  5.   ;;   ("Model"
  6.   ;;     ("ROOM TAG" ("AREA_NAME_1" "123" "AREA")
  7.   ;;     ("AREA_NAME_2" "123" "AREA")
  8.   ;;     ...
  9.   ;;     (<Tag Name N> <Value1> ... <ValueN>))
  10.   ;;   ...
  11.   ;;   (<Block Name N>
  12.   ;;     (<Tag Name 1> <Value1> ... <ValueN>)
  13.   ;;     ...
  14.   ;;     (<Tag Name N> <Value1> ... <ValueN>))))
  15. )
hello irneb

i think i can handle to fill all list_box with nth or mapcar.

main problem is how to obtain position on my LST when i select something at dcl?
since i'm filter LST (maybe sort at some list_box) this is not easy i guess ?

thanks
kruuger

Lee Mac

  • Seagull
  • Posts: 12926
  • London, England
Re: List manipulation (dcl list_box)
« Reply #5 on: January 30, 2013, 06:50:50 AM »
Good suggestion Irneb, nth would be more suitable for this application.

main problem is how to obtain position on my LST when i select something at dcl?

The index of the selected item in a list_box or popup_list DCL tile is held by the $value action expression which may be accessed from within the action_tile statement for the tile, e.g.:

Code: [Select]
(action_tile <DCL-tile> "(setq idx $value)")
Here, the idx symbol would hold a string containing the zero-based indexes of the selected item(s) in the list_box or popup_list.

since i'm filter LST (maybe sort at some list_box) this is not easy i guess ?

Since you are populating each list_box with a list of items retrieved from the main data (based on selected items from other list boxes), you can use the index of the selected item (as described above) to retrieve the selected item from the list of items populating the current list_box.

Alternatively, if the lists were not going to be sorted independently of the main data list, you could use a list of indexes of the selected items in each list_box to retrieve a corresponding list of selected items from the main data list.

For example, if your main data was:
(I missed the last level of nesting in my earlier post)

Code: [Select]
(setq data       
   '(
        (   "Drawing1"
            (   "Layout1"
                (   "Block1"
                    (   "Tag1"
                        (   "Value1" "Value2"   )
                    )
                    (   "Tag2"
                        (   "Value1" "Value2"   )
                    )
                )
                (   "Block2"
                    (   "Tag1"
                        (   "Value1" "Value2"   )
                    )
                    (   "Tag2"
                        (   "Value1" "Value2"   )
                    )
                )
            )
            (   "Layout2"
                (   "Block1"
                    (   "Tag1"
                        (   "Value1" "Value2"   )
                    )
                    (   "Tag2"
                        (   "Value1" "Value2"   )
                    )
                )
                (   "Block2"
                    (   "Tag1"
                        (   "Value1" "Value2"   )
                    )
                    (   "Tag2"
                        (   "Value1" "Value2"   )
                    )
                )
            )
        )
        (   "Drawing2"
            (   "Layout1"
                (   "Block1"
                    (   "Tag1"
                        (   "Value1" "Value2"   )
                    )
                    (   "Tag2"
                        (   "Value1" "Value2"   )
                    )
                )
                (   "Block2"
                    (   "Tag1"
                        (   "Value1" "Value2"   )
                    )
                    (   "Tag2"
                        (   "Value1" "Value2"   )
                    )
                )
            )
            (   "Layout2"
                (   "Block1"
                    (   "Tag1"
                        (   "Value1" "Value2"   )
                    )
                    (   "Tag2"
                        (   "Value1" "Value2"   )
                    )
                )
                (   "Block2"
                    (   "Tag1"
                        (   "Value1" "Value2"   )
                    )
                    (   "Tag2"
                        (   "Value1" "Value2"   )
                    )
                )
            )
        )
    )
)

Such a function might be:

Code - Auto/Visual Lisp: [Select]
  1. (defun _getitems ( idx data / n )
  2.     (if idx
  3.         (cons
  4.             (car (setq n (nth (car idx) data)))
  5.             (_getitems (cdr idx) (cdr n))
  6.         )
  7.     )
  8. )

Which you would then call with the main data list and a list of indexes for each level of the data:

Code - Auto/Visual Lisp: [Select]
  1. _$ (_getitems '(1 0 1 1 0) data)
  2. ("Drawing2" "Layout1" "Block2" "Tag2" "Value1")

Sorry if this isn't explained too well.
« Last Edit: January 30, 2013, 06:54:00 AM by Lee Mac »

kruuger

  • Swamp Rat
  • Posts: 637
Re: List manipulation (dcl list_box)
« Reply #6 on: January 30, 2013, 07:07:39 AM »
Thanks Lee for sample and explanation. All is clear. _GetItems - thats clever :)

However all these above will work only without any "modification" to each list_box list.
At list_box with block names i want to delete duplicates of the same name (unique list) and then _GetItems will not work. I'm correct ?

How advanced need to be code to handle: sort, unique list, maybe something else.

kruuger

EDIT: forgot. some list_box have multiple_select = true

Lee Mac

  • Seagull
  • Posts: 12926
  • London, England
Re: List manipulation (dcl list_box)
« Reply #7 on: January 30, 2013, 07:15:26 AM »
Thanks Lee for sample and explanation. All is clear. _GetItems - thats clever :)

Thank you kruuger  :-)

However all these above will work only without any "modification" to each list_box list.
At list_box with block names i want to delete duplicates of the same name (unique list) and then _GetItems will not work. I'm correct ?

Correct, as noted, the sample '_getitems' function would only work if the list_box data matches the main data list.

Though, as far as I was aware, there would never be duplicate items, since such items would be grouped together in the main list as both would share the same 'parent'.

As for sorting, you would need to maintain a separate list for each list_box, and retrieve the item at the selected index for each of these lists (as noted above); for this case you would also need to use assoc to update the remaining list boxes, since the order of the list box data may not necessarily match the order of the main list.

The case of multiple_select = true would just require you to retrieve multiple items from each of these separate lists.
« Last Edit: January 30, 2013, 07:18:43 AM by Lee Mac »

kruuger

  • Swamp Rat
  • Posts: 637
Re: List manipulation (dcl list_box)
« Reply #8 on: January 30, 2013, 07:43:53 AM »
Though, as far as I was aware, there would never be duplicate items, since such items would be grouped together in the main list as both would share the same 'parent'.
for example we can read inserts from dwg and there will be few blocks with the same name. so we need to make a unique list to display only one name

As for sorting, you would need to maintain a separate list for each list_box, and retrieve the item at the selected index for each of these lists (as noted above); for this case you would also need to use assoc to update the remaining list boxes, since the order of the list box data may not necessarily match the order of the main list.
ok, i think i got this

thanks for help. i will try to wrote something and share.
kruuger

Lee Mac

  • Seagull
  • Posts: 12926
  • London, England
Re: List manipulation (dcl list_box)
« Reply #9 on: January 30, 2013, 08:12:19 AM »
Though, as far as I was aware, there would never be duplicate items, since such items would be grouped together in the main list as both would share the same 'parent'.
for example we can read inserts from dwg and there will be few blocks with the same name. so we need to make a unique list to display only one name

But those blocks with the same name would appear in the main list under the single block name, for example, as generated by the following function:

Code: [Select]
(defun c:makelist ( / a e i l n r s x z )
    (if (setq s (ssget '((0 . "INSERT") (66 . 1))))
        (repeat (setq i (sslength s))
            (setq e (ssname s (setq i (1- i)))
                  n (cdr (assoc 2 (entget e)))
                  e (entnext e)
                  l (entget  e)
                  a nil
            )
            (while (= "ATTRIB" (cdr (assoc 0 l)))
                (setq a (cons (list (cdr (assoc 2 l)) (list (cdr (assoc 1 l)))) a)
                      e (entnext e)
                      l (entget  e)
                )
            )
            (if (setq x (cdr (assoc n r)))
                (progn
                    (foreach y a
                        (if (setq z (assoc (car y) x))
                            (setq x (subst (list (car y) (cons (caadr y) (cadr z))) z x))
                            (setq x (cons y x))
                        )
                    )
                    (setq r (subst (cons n x) (assoc n r) r))
                )
                (setq r (cons (cons n a) r))
            )
        )
    )
    r
)

thanks for help. i will try to wrote something and share.

You're welcome kruuger  :-)

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: List manipulation (dcl list_box)
« Reply #10 on: January 30, 2013, 08:43:28 AM »
Yes that was my understanding too, i.e. your data list formed like this:
Code: [Select]
("DrawingPath"
    ("Model" "Layout1" ... "LayoutN")
    ("Block1"
        ("Tag1" "Value1" ... "ValueN")
        ...
        ("TagN" "Value1" ... "ValueN"))
    ...
    ("BlockN"
        ("Tag1" "Value1" ... "ValueN")
        ...
        ("TagN" "Value1" ... "ValueN")))
Thus you handle the multiple references of the same block by listing all values found in each tag sublist.

Lee's tip about the $value parameter is generally better to use than my method with get_tile. Unfortunately $value only works on the tile which is issuing the "event". So if you have a button to press, the $value would simply return the button's label. Thus you might need to use get_tile for other ideas too, e.g. on your Tags list you might need to check the selections on the other lists as well to get to the correct tag sublist in the full data list.

Either way (get_tile / $value) you can still use multiple selection list_boxes too. E.g. say the user selected 1st, 3rd & 4th items, then both $value and get_tile would return "0 2 3". And to get that into a list of indexes I like this method because it's so much less to type:
Code - Auto/Visual Lisp: [Select]
  1. (read (strcat "(" $value ")")) ;Returns (0 2 3)
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

kruuger

  • Swamp Rat
  • Posts: 637
Re: List manipulation (dcl list_box)
« Reply #11 on: January 30, 2013, 12:34:10 PM »
thanks gentlemens:)

Lee your code make me a headache but slowly everything starts to be clear.

what list are you suggest to use to work with DBX? instead of all data previously described i think we need VLA (handle or just vla-object) of each block (AcDbBlockReference).
maybe
Code: [Select]
("DrawingPath"
    ("Model"
      ("Block1"
        (Vla1 ??
            ("Tag1" "Value1")
            ...
        (VlaN ??
            ("TagN" "Value1")))
      ...
      ("BlockN"
        (Vla1 ??
          ("Tag1" "Value1")
          ...
         
          ("TagN" "Value1")))
    ("Layout1"
      ("Block1"
        (Vla1 ??
            ("Tag1" "Value1")
            ...
        (VlaN ??
            ("TagN" "Value1"))
      ...
      ("BlockN"
        (Vla1 ??
          ("Tag1" "Value1")
            ...
        (VlaN ??
          ("TagN" "Value1")))
how to keep this list flexible ? maybe later we want add something else.

kruuger
« Last Edit: January 30, 2013, 12:54:26 PM by kruuger »

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: List manipulation (dcl list_box)
« Reply #12 on: January 30, 2013, 11:37:59 PM »
what list are you suggest to use to work with DBX? instead of all data previously described i think we need VLA (handle or just vla-object) of each block (AcDbBlockReference).
I wouldn't do that, rather just use the block's name. The vla-object is only of use while the DBX document is open. Are you keeping all the documents open while the dialog is displayed?

Not to mention, the vla-object is unique for each and every copy of the same block, so you could theoretically have a listbox for Blocks displayed as:
Quote
ROOM_TAG
ROOM_TAG
ROOM_TAG
ROOM_TAG
ROOM_TAG
ROOM_TAG
ROOM_TAG
...
How are you going to know which one of those is which? The vla-object's ObjectID is simply a auto-generated number - not much interest for a user, the handle / ename is much the same. The only "known" difference would be the attributes' values (at least as I understand this).
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

kruuger

  • Swamp Rat
  • Posts: 637
Re: List manipulation (dcl list_box)
« Reply #13 on: January 31, 2013, 03:04:42 AM »
what list are you suggest to use to work with DBX? instead of all data previously described i think we need VLA (handle or just vla-object) of each block (AcDbBlockReference).
I wouldn't do that, rather just use the block's name. The vla-object is only of use while the DBX document is open. Are you keeping all the documents open while the dialog is displayed?

Not to mention, the vla-object is unique for each and every copy of the same block, so you could theoretically have a listbox for Blocks displayed as:
Quote
ROOM_TAG
ROOM_TAG
ROOM_TAG
ROOM_TAG
ROOM_TAG
ROOM_TAG
ROOM_TAG
...
How are you going to know which one of those is which? The vla-object's ObjectID is simply a auto-generated number - not much interest for a user, the handle / ename is much the same. The only "known" difference would be the attributes' values (at least as I understand this).
1. i want to "connect" to file via DBX when select file at list_box. read all data and display at dcl
2. there will few blocks with the same name so i think i need to store handle of each block. when i close the dcl i will need to again connect to file to read additional data (insertion point, layer, whatever else). handle will be helpful i think
this is some kind of drawing block attributes viewer.

i already do something but i "turned in the code" a little (see gif)

kruuger

togores

  • Guest
Re: List manipulation (dcl list_box)
« Reply #14 on: January 31, 2013, 01:27:29 PM »
This program would be great if done with OpenDCL, using a non-modal palette form with a Tree control on it.
This way you could have a hierarchical tree view showing the drawings on the upper level, the layers on a second one, the blocks in each drawing as a third level and the attributes as a fourth level.
Choosing a node could then display the attribute data on a list view.
To show the idea I'm attaching an image showing a form of this kind created with OpenDCL. In this case it shows drawings and layers, but the tree view could be extended to include nodes for the blocks and the attributes. This form can remain open when a different drawing is activated and updating automatically.
Having the info in a single container (the Tree control) simplifies doing any kind of search, including multiple selections. Although LeeMac's recursive function for the data collected in the nested list is beautiful.
This image is from the tutorial in Chapter 27 of my book on AutoLISP programming.