LISP find block by Block Name AND where Attribute TAG1=*User Input*

LISP find block by Block Name AND where Attribute TAG1=*User Input*

david.faunce
Enthusiast Enthusiast
5,964 Views
6 Replies
Message 1 of 7

LISP find block by Block Name AND where Attribute TAG1=*User Input*

david.faunce
Enthusiast
Enthusiast

I'm new to AutoLISP. I've gone through many tutorials most of which just show you math and how to loop. There are only a handful of tutorials that deal with acutal block manipulation which is where I struggle.

 

I've seen some of the great LISP functions that Lee Mac and Nate Holt (and others) have created and shared, but I have yet to find a routine that does the following:

 

(1) Find the block where BLOCK NAME = "VIFCD_001" AND ATTRIBUTE  [TAG1] = "-M161"

(2) Inside that same block change the ATTRIBUTE [DESC] = "NEW PART NUMBER"

 

I would prefer that "BLOCK NAME"   "TAG NAME"  and "DESC NAME" be arguments in a function.

 

I've been trying to work from this routine (below), that will change attributes of a block. The only LISP routine I know prompts the user to select the block, however, I cannot prompt the user for anything - I need the block name to be passed as an argument

 

How do I use LISP to select the block where BLOCK NAME = "VIFCD_001" and its attribute TAG1="-M161"

 

 

THE CALL

(setq ent (car (entsel)))  ;Prompts the user to select a block
(changeVars "DESC" "NEW PART NUMBER" ent)

 

 

THE FUNCTION

(defun changeVars (tag newvalue ent / alist)
  (if (and (= (type ent) (read "VLA-OBJECT")) newvalue)
    (progn
      (setq alist ( vlax-invoke ent 'GetAttributes))
      (foreach a alist)
         (if (= (vla-get-tagstring a) tag)
             (vlax-put-property a 'TextString newvalue)
         );endif
       );end foreach
     );end progn
     (if (= 'ename (type ent)) 
         (reptag tag newvalue (vlax-ename->vla-object ent))
     );endif
   );endif
(princ)
);end defun

 

 

 

Accepted solutions (1)
5,965 Views
6 Replies
Replies (6)
Message 2 of 7

Ranjit_Singh
Advisor
Advisor

Here is one example.

;;Ranjit Singh
;;8/3/17
(defun somefunc (tagname value blockname / etdata) (mapcar '(lambda (x) (while (/= "SEQEND" (cdr (assoc 0 (setq etdata (entget (setq x (entnext x))))))) (and (= (cdr (assoc 0 etdata)) "ATTRIB") (mapcar '(lambda (x y) (and (= x (cdr (assoc 2 etdata))) (entmod (subst (cons 1 y) (assoc 1 etdata) etdata)))) (list tagname) (list value))))) (mapcar 'cadr (ssnamex (ssget "_x" (list '(0 . "insert") (cons 2 blockname) '(66 . 1)))))))

Update_Block_Attribute.gif

EDIT: If you want to pass ent then change this

(mapcar 'cadr (ssnamex (ssget "_x" (list '(0 . "insert") (cons 2 blockname) '(66 . 1)))))

to

(mapcar 'cadr (ssnamex (ssget "_x" (list '(0 . "insert") (assoc 2 (entget blockname)) '(66 . 1)))))

 and call the function like

(somefunc "DESC" "NEW PART NUMBER" ent)

 Update_Block_Attribute_2.gif

0 Likes
Message 3 of 7

david.faunce
Enthusiast
Enthusiast

Thank you Ranjit. 

 

This is helpful, however, I was hoping to have the user not select the object.

 

This function will need to be purely automated without any prompts for the user to select objects or type inputs.

 

 

 

I need to select the block where BLOCK NAME = VIFCD_001  and its attribute TAG1 = "-M161"

 

 

*this command below is wrong, but my question to you is how do I use LISP to identify a block where BLOCKNAME="VIFCD_001" AND TAG1="-M161"*

(setq ent (entsel <block name>  <tag name>))
(setq ent (entsel "VIFCD_001",  "-M161"))

 

0 Likes
Message 4 of 7

david.faunce
Enthusiast
Enthusiast

I think I'm getting close, but can someone help? This produces a NIL value, but I believe these are the properties I need to access.

 

(setq ss (ssget "_X" '((0 . "INSERT") (2 . "VIFCD_001") (5 . "1C7F"))))

 

 

Below are the properties for two blocks (both named VIFCD_001)

 

 

 

Properties for Block #1

(
  (-1 . <Entity name: 3aceb1f0>)
  (0 . "INSERT")
  (330 . <Entity name: 35557820>)
  (5 . "1C7F")
  (100 . "AcDbEntity")
  (67 . 0)
  (410 . "Model")
  (8 . "Syms")
  (100 . "AcDbBlockReference")
  (66 . 1)
  (2 . "VIFCD_001")
  (10 0.0867055 5.14515e-06 0.0)
  (41 . 1.0)
  (42 . 1.0)
  (43 . 1.0)
  (50 . 0.0)
  (70 . 0)
  (71 . 0)
  (44 . 0.0)
  (45 . 0.0)
  (210 0.0 0.0 1.0)
)

 

Properties for Block #2

(
  (-1 . <Entity name: 3acea5b0>)
  (0 . "INSERT")
  (330 . <Entity name: 35557820>)
  (5 . "1C43")
  (100 . "AcDbEntity")
  (67 . 0)
  (410 . "Model")
  (8 . "Syms")
  (100 . "AcDbBlockReference")
  (66 . 1)
  (2 . "VIFCD_001")
  (10 145.197 0.100673 0.0)
  (41 . 1.0)
  (42 . 1.0)
  (43 . 1.0)
  (50 . 0.0)
  (70 . 0)
  (71 . 0)
  (44 . 0.0)
  (45 . 0.0)
  (210 0.0 0.0 1.0)
)

0 Likes
Message 5 of 7

Ranjit_Singh
Advisor
Advisor

@david.faunce wrote:

Thank you Ranjit. 

 

This is helpful, however, I was hoping to have the user not select the object.

 

This function will need to be purely automated without any prompts for the user to select objects or type inputs.

 

 

 

I need to select the block where BLOCK NAME = VIFCD_001  and its attribute TAG1 = "-M161"

 

 

*this command below is wrong, but my question to you is how do I use LISP to identify a block where BLOCKNAME="VIFCD_001" AND TAG1="-M161"*

(setq ent (entsel <block name>  <tag name>))
(setq ent (entsel "VIFCD_001",  "-M161"))

 



There has to be some way to identify the block. Block name is one. Other could be block insertion point if you are after a particular block. If you want to update a tag in any instance of the block then you just create a selection set of all the blocks and then iterate through them. My example is good for plugging in your overall function? I thought that was the goal since you needed a function with arguments. Something like this

(defun c:somefunc  (/ ctr ss1)
  (setq ctr 0
        ss1 (ssget "_x" '((0 . "insert") (2 . "VIFCD_001"))))
  (repeat (sslength ss1) (somefunc "DESC" "NEW PART NUMBER" (ssname ss1 ctr)) (setq ctr (1+ ctr))))

(defun somefunc  (tagname value blockname / etdata)
  (mapcar '(lambda (x)
             (while (/= "SEQEND" (cdr (assoc 0 (setq etdata (entget (setq x (entnext x)))))))
               (and (= (cdr (assoc 0 etdata)) "ATTRIB")
                    (mapcar '(lambda (x y)
                               (and (= x (cdr (assoc 2 etdata))) (entmod (subst (cons 1 y) (assoc 1 etdata) etdata))))
                            (list tagname)
                            (list value)))))
          (mapcar 'cadr (ssnamex (ssget "_x" (list '(0 . "insert") (assoc 2 (entget blockname)) '(66 . 1)))))))

Update_Block_Attribute_3.gif 

Is there something I am missing?

Message 6 of 7

Ranjit_Singh
Advisor
Advisor
Accepted solution

@david.faunce wrote:

I think I'm getting close, but can someone help? This produces a NIL value, but I believe these are the properties I need to access.

 

(setq ss (ssget "_X" '((0 . "INSERT") (2 . "VIFCD_001") (5 . "1C7F")))) ;

 

.................


You cannot use dxf code 5 in ssget. Read here The ssget function recognizes all group codes except entity names (group code -1), handles (group code 5), and .... If you have the entity handle from some previous data processing and want to select an object with a particular handle, for instance, "1C7F" then call hadnet

(handent "1C7F")

 

Message 7 of 7

david.faunce
Enthusiast
Enthusiast

This is very helpful...I have not heard about "handent" thank you!

0 Likes