Search code examples
autocadautocad-pluginautolisp

how to change attribute of block using ObjectDBX


I need to change an attribute of drawing with the ObjectDBX method using AutoLISP. this routine run properly but not change the attribute,can you suggest any change in code or any other method to achieve this task? Thank you.

;;;;;;;;;;;;;;;;;;;

(defun DBX_ATT_CHANGE (f)
  (vl-load-com)
  (setq cadver (substr (getvar "acadver") 1 2))
  (setq id (strcat "objectdbx.AxDbDocument." cadver))
  (setq dbx (vlax-create-object id))
  (vla-open dbx f)

  (vlax-for n_object (vla-get-modelspace dbx)
    (setq dbx_en (vlax-vla-object->ename n_object))


    (setq upc_blkobj (vlax-ename->vla-object dbx_en))



    (if (vlax-method-applicable-p upc_blkobj 'GetAttributes)

      (progn
    (setq upc_attlist

           (vlax-invoke upc_blkobj 'GetAttributes)
    )

    (foreach upc_att upc_attlist
      (progn
        (if (= (vla-get-tagstring upc_att) (strcase "P_TAG1"))
          (vlax-put-property
        upc_att
        'TextString
        "555"
          )
        )
      )
    )
      )
    )
    (vlax-release-object upc_blkobj)


  )



  (vla-saveas dbx dwgfile)
  (vlax-release-object dbx)
  (prin1)
)
(defun c:test ()
  (DBX_ATT_CHANGE
    "D:/6. R&D/Delet Group LispDBXapi/7-EU-FE-48-AC-CIOC-SA - Copy.dwg"

  )
)

;;;;;;;;;;;;;;;


Solution

  • There are a couple of oddities present in your current code:


    1. (setq dbx_en (vlax-vla-object->ename n_object))
      (setq upc_blkobj (vlax-ename->vla-object dbx_en))
      

      You are converting the vla-object n_object into an entity name dbx_en, and then converting this entity name back into a vla-object upc_blkobj. These two lines are redundant, as you can work with the n_object variable directly.


    1. (= (vla-get-tagstring upc_att) (strcase "P_TAG1"))
      

      You are using strcase to convert a literal uppercase string P_TAG1 to uppercase, and then comparing this uppercase string to a string which may or may not be uppercase - I believe this line should be:

      (= (strcase (vla-get-tagstring upc_att)) "P_TAG1")
      

    To offer you an alternative for this task, you could make use of my ObjectDBX Wrapper function, which provides a way to evaluate a given function on another drawing or set of drawings, without opening such drawings in the AutoCAD Editor.

    I would personally write your code in the following way:

    (defun c:test ( )
        (LM:DBXAttChange
            "D:\\6. R&D\\Delet Group LispDBXapi\\7-EU-FE-48-AC-CIOC-SA - Copy.dwg"
            '(("P_TAG1" . "555"))
        )
        (princ)
    )       
    
    (defun LM:DBXAttChange ( dwg lst / doc flg val )
        (if (setq doc (LM:GetDocumentObject dwg))
            (progn
                (vlax-for lyt (vla-get-layouts doc)
                    (vlax-for obj (vla-get-block lyt)
                        (if (and (= "AcDbBlockReference" (vla-get-objectname obj))
                                 (= :vlax-true (vla-get-hasattributes obj))
                            )
                            (foreach att (vlax-invoke obj 'getattributes)
                                (if (and (setq val (cdr (assoc (strcase (vla-get-tagstring att)) lst)))
                                         (vlax-write-enabled-p att)
                                    )
                                    (progn
                                        (vla-put-textstring att val)
                                        (setq flg t)
                                    )
                                )
                            )
                        )
                    )
                )
                (if flg (vla-saveas doc dwg))
                (vlax-release-object doc)
                flg
            )
            (prompt (strcat "\nThe drawing \"" dwg "\" was not found or could not be accessed."))
        )
    )
    
    ;; Get Document Object  -  Lee Mac
    ;; Retrieves the VLA Document Object for the supplied filename.
    ;; The Document Object may be present in the Documents collection, or obtained through ObjectDBX.
    ;; It is the callers responsibility to release such object.
    
    (defun LM:GetDocumentObject ( dwg / app dbx dwl err vrs )
        (cond
            (   (not (setq dwg (findfile dwg))) nil)
            (   (cdr
                    (assoc (strcase dwg)
                        (vlax-for doc (vla-get-documents (setq app (vlax-get-acad-object)))
                            (setq dwl (cons (cons (strcase (vla-get-fullname doc)) doc) dwl))
                        )
                    )
                )
            )
            (   (progn
                    (setq dbx
                        (vl-catch-all-apply 'vla-getinterfaceobject
                            (list app
                                (if (< (setq vrs (atoi (getvar 'acadver))) 16)
                                    "objectdbx.axdbdocument" (strcat "objectdbx.axdbdocument." (itoa vrs))
                                )
                            )
                        )
                    )
                    (or (null dbx) (vl-catch-all-error-p dbx))
                )
                (prompt "\nUnable to interface with ObjectDBX.")
            )
            (   (vl-catch-all-error-p (setq err (vl-catch-all-apply 'vla-open (list dbx dwg))))
                (prompt (strcat "\n" (vl-catch-all-error-message err)))
            )
            (   dbx   )
        )
    )
    
    (vl-load-com) (princ)