Best way to access attribute information in a multileader.

Hi.

I want to make a lisp that shunts number sequences either up or down so that when I miss an item I don't have to renumber all the numbers. I have attached my Item multileader.

I'm not sure of the best way to address the multileaders's attribute data. I think "assoc 302 ..... " will address the text in the attribute. But I think I am missing a better way.

Comments

  • ALANH
    edited September 2022
    Part 1 how to modify

    I spent a bit of time and found this answer By Lee. I changed 2 lines to make it work for your dwg.

    ;; Set MLeader Block Attribute Value - Lee Mac
    ;; mld - [vla] MLeader object with attributed block content
    ;; tag - [str] Attribute tag whose value will be modified
    ;; val - [str] New attribute value

    ;(defun LM:setmleaderblockattributevalue ( mld tag val )
    (defun LM:setmleaderblockattributevalue ( mld val )
    (if (= acblockcontent (vla-get-contenttype mld))
    (vl-catch-all-error-p
    (vl-catch-all-apply
    '(lambda ( / oid )
    (vlax-for obj
    (vla-item
    (vla-get-blocks (vla-get-document mld))
    (vla-get-contentblockname mld)
    )
    (if (and (= "AcDbAttributeDefinition" (vla-get-objectname obj))
    (= :vlax-false (vla-get-constant obj))
    ; (= (strcase tag) (strcase (vla-get-tagstring obj)))
    )
    (progn
    (if (vlax-property-available-p obj 'objectid32)
    (setq oid (vla-get-objectid32 obj))
    (setq oid (vla-get-objectid obj))
    )
    (if (vlax-method-applicable-p mld 'setblockattributevalue32)
    (vla-setblockattributevalue32 mld oid val)
    (vla-setblockattributevalue mld oid val)
    )
    (exit)
    )
    )
    )
    )
    )
    )
    )
    )

    ; Possible solution by AlanH Consulting
    ; credit to Lee for solution of modify leader text.
    ; tag search removed for block with only 1 attribute
    ; Sep 2022

    (defun c:wow ( / ss lst ent num302num minnum entl obj lnum)
    (prompt "\nSelect all leaders")
    (setq ss (ssget '((0 . "MULTILEADER"))))
    (if (= ss nil)
    (alert "No leaders were selected ")
    (progn
    (setq lst '())
    (repeat (setq x (sslength ss))
    (setq ent (entget (ssname ss (setq x (1- x)))))
    (setq num302 (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 302)) ent)))
    (setq num (atoi (cadr num302)))
    (setq lst (cons (list num (cdr (assoc -1 ent))) lst))
    )

    (setq lst (vl-sort lst '(lambda (x y) (< (car x)(car y)))))
    (setq minnum (car (car lst)))
    (setq lnum (getint (strcat "\nCurrent min No. is " (rtos minnum 2 0) " Enter new number ")))
    (foreach entl lst
    (setq obj (vlax-ename->vla-object (cadr entl)))
    (LM:setmleaderblockattributevalue obj (rtos lnum 2 0))
    (setq lnum (1+ lnum))
    )
    )
    )
    (princ)
    )
    (c:wow)
  • Did Lee Mac really write the c:wow function?
  • ALANH
    edited September 2022
    No that was me, but with out the great code from Lee I would not have solved the request. Change "wow" to what you want. Have a look at "Lee-mac.com"

    Changed post slightly.

    Needs the Plus, Minus to be added.

    If you window select it will update in creation order, if want in some sort of pattern then use pick pick pick when asked to select for order.
  • Here is a very basic solution. The last attribute of the MLeader block is updated. Tested on V18.
    (defun c:ML-Shunt ( / blk delta doc enm num rev-elst ss sta)
      (setq doc (vla-get-activedocument (vlax-get-acad-object)))
      (vla-endundomark doc)
      (vla-startundomark doc)
      (if
        (and
          (setq enm (car (entsel "\nSelect MLeader with correct block: ")))
          (= "MULTILEADER" (vle-entget 0 enm))
          (= 1 (vle-entget 296 enm))      ; HasBlock.
          (setq blk (vle-entget 341 enm)) ; Block definition.
          (setq sta (getint "\nStart number (MLeaders with this and a higher number are processed): "))
          (setq delta (getint "\nDelta value (can be negative): "))
          (setq ss (ssget "_X" (list '(0 . "MULTILEADER") '(296 . 1) (cons 341 blk) '(302 . "#,##,###"))))
        )
        (foreach enm (vle-selectionset->list ss)
          (setq rev-elst (reverse (entget enm)))
          (setq num (atoi (cdr (assoc 302 rev-elst))))
          (if (<= sta num)
            (entmod
              (reverse
                (subst
                  (cons 302 (itoa (+ num delta)))
                  (assoc 302 rev-elst)
                  rev-elst
                )
              )
            )
          )
        )
      )
      (vla-endundomark doc)
      (princ)
    )
  • Nice code, only problem is if in office and they have Autocad it will not work, same with other clone cad.

    The vle has advantages but other Cad is its disadvantage. I have CIV3D and Bricscad.
  • ALANH said:

    Nice code, only problem is if in office and they have Autocad it will not work, same with other clone cad.

    The vle has advantages but other Cad is its disadvantage. I have CIV3D and Bricscad.

    The VLE library of functions have also been made available for other CAD platforms that use lisp. Just need to include and load "vle-extension.lsp", which you will find in the BricsCAD program folder. It is also available in the Lisp Developer Support Package (LDSP).

    The "vle-extension.lsp" is also safe to load in BricsCAD too, only defining functions if they don't already exist. This can be useful if you're trying to maintain support with older releases of BricsCAD.


    Regards,
    Jason Bourhill
    BricsCAD V22 Ultimate
    CAD Concepts
  • Thanks for the information.
  • Thanks guys. This is quite a bit for me to digest. I'm still very new to LISP.
  • Here is a very basic solution. The last attribute of the MLeader block is updated. Tested on V18.

    (defun c:ML-Shunt ( / blk delta doc enm num rev-elst ss sta)
      (setq doc (vla-get-activedocument (vlax-get-acad-object)))
      (vla-endundomark doc)
      (vla-startundomark doc)
      (if
        (and
          (setq enm (car (entsel "\nSelect MLeader with correct block: ")))
          (= "MULTILEADER" (vle-entget 0 enm))
          (= 1 (vle-entget 296 enm))      ; HasBlock.
          (setq blk (vle-entget 341 enm)) ; Block definition.
          (setq sta (getint "\nStart number (MLeaders with this and a higher number are processed): "))
          (setq delta (getint "\nDelta value (can be negative): "))
          (setq ss (ssget "_X" (list '(0 . "MULTILEADER") '(296 . 1) (cons 341 blk) '(302 . "#,##,###"))))
        )
        (foreach enm (vle-selectionset->list ss)
          (setq rev-elst (reverse (entget enm)))
          (setq num (atoi (cdr (assoc 302 rev-elst))))
          (if (<= sta num)
            (entmod
              (reverse
                (subst
                  (cons 302 (itoa (+ num delta)))
                  (assoc 302 rev-elst)
                  rev-elst
                )
              )
            )
          )
        )
      )
      (vla-endundomark doc)
      (princ)
    )
    Thanks. I finally managed to write working code modeled on your solution. I had to write my own so as to learn and because I'm not a cut and paste person.
    ;Bump a number into a sequence of number attrubutes
    ;First determine the number of the attribute
    
    (defun c:ipush ( / leaderx leaderxp lnostr lno blk )
    
     (setq leaderx (entsel  "\nSelect a multileader"))
     (setq leaderxp (entget (car leaderx)))
     (if 
         (and
    	(= (cdr (assoc 0 leaderxp)) "MULTILEADER") ; Checks that a multileader was selected
    	(= (cdr (assoc 296 leaderxp)) 1)					;Checks that multileder has a block
    	(= (cdr (assoc 2 (entget (cdr (assoc 341 leaderxp))))) "ItemLabel") ;The name of my label block in my leader is "ItemLabel" 
    		)
    	(progn
    	 (setq lnostr (cdr (assoc 302 (cdr (member (assoc 302 leaderxp) leaderxp))))) ; "lnostr" short for leader number string
    			
    	 (setq lno (atoi lnostr))			;Gets integer value of leader number string
    	  (setq blk (cdr (assoc 341 leaderxp)))  ;Get the block entity Id
    											
    	  (print "IT'S AN ATTRIBUTE MULTILEADER")
    	  (pushnumbers blk lno)
    	  (entmod (subst lnostr (cdr (assoc 302 (cdr (member (assoc 302 leaderxp) leaderxp)))) leaderxp)) ;restores the selected item label to its inserted value
    	;Note: " (cdr (member (assoc 302).... " is used to get past first 302 item in entget	
    			
    	)
    	(progn 
    	  (alert "SORRY THAT IS NOT AN ITEM NUMBER MULTILEADER")
    	  (print (car (assoc 2 (entget (cdr (assoc 341 leaderxp))))) )
    	)
    	)
    (princ)	
    )
    
    	
    	
    
    (defun pushnumbers ( blk lno / ss num)
    
      (setq ss (ssget "X" (list '(0 . "MULTILEADER") '(296 . 1) (cons 341 blk))))
    	
    
      (foreach enm (vle-selectionset->list ss)
    		
        (setq elist (entget enm)	)
        (setq num (atoi (cdr (assoc 302 (cdr(member (assoc 302 elist) elist))))))
    		
          (if (<= lno num)
    			
            (entmod
                (subst 
                   (cons 302 (itoa (1+ num)))	
                   (assoc 302 (cdr (member (assoc 302 elist) elist	) ))
                elist)
            )
    				
      )
    (entupd enm)
    )
    
    )