Jump to content

Setting Visibility State based on Attribute value


Nomad

Recommended Posts

Sorry - I allready changed the block name to circle and the lisp file. That is not the problem...

Anyway I tried your examples:

GstarCAD pro 2020 message: "No attributed 'Cabinet' blocks found in the drawing." 

AutoCAD 2020 message: "no function definition: VLAX-ENAME->VLA-OBJECT"

 

Crazy...

 

 

Link to comment
Share on other sites

12 hours ago, Ecko said:

Sorry - I allready changed the block name to circle and the lisp file. That is not the problem...

Anyway I tried your examples:

GstarCAD pro 2020 message: "No attributed 'Cabinet' blocks found in the drawing." 

AutoCAD 2020 message: "no function definition: VLAX-ENAME->VLA-OBJECT"

 

Crazy...

 

 

 

I can't help with GstarCAD, but the original problem was caused by the inserted block being called "circle" and not "cabinet". Since "cabinet" is the effective name of the block reference it is looking for, and there isn't one; you can't change a visibility state of a block reference that doesn't exist.

 

There is/was definitely a (vl-load-com) in the lisp I attached, so the "no function definition: VLAX-ENAME->VLA-OBJECT" probably means that vlisp itself isn't loading or didn't load properly. 

Link to comment
Share on other sites

...  the circle <=> cabinet thing was not the problem. I changed both files to circle and back to cabinet. 

Anyway I used your example files to avoid errors and they are perfekt (and have less code). 

Forget GstarCAD ... How can I activate or repair vlisp in AutoCAD or how can I test if vlisp is working properly?

 

Link to comment
Share on other sites

Well, I found the problem... AutoCAD Architecture 2020 had a problem activating Active-X. I found a regestry hack

and finaly I works! Yee-Haw! Thanks for your patience and your help!

  • Like 1
Link to comment
Share on other sites

1 hour ago, Ecko said:

Well, I found the problem... AutoCAD Architecture 2020 had a problem activating Active-X. I found a regestry hack

and finaly I works! Yee-Haw! Thanks for your patience and your help!

 

Glad you got it sorted. 👍

  • Like 1
Link to comment
Share on other sites

  • 10 months later...

Hey, everyone. I could use a hand figuring out how to run this multiple times with different blocks. Every time I try to extend the code out, it only triggers the first visibility state. Any chance someone could help me figure out how to set this code up to run with a second visibility state of a separate block? I'm trying to search the forum for an idea of how to compile multiple LISPs now, but wondering if there's a better way to do it with variables or something.

Thank you so much to everyone for supplying this code. I have very little experience with LISP, but I have a modified version of this running for the most part. I altered the code to reference an attribute in one block and then change the visibility of a second block. I import attributes from excel with AttIn to a static table that doesn't change blockname like the dynamic blocks do when you change visibility state. Then I trigger the LISP to change the visibility state of the correlating detail. The only problem is I can't figure out how to compile multiple iterations of such a program into one LISP. I can macro each detail into its own LISP, but for the sake of simplicity, it would obviously be best if it was one button/trigger.

 

Also is there any reason the blocks have to have an attribute? Racked my brain for why the block won't change visibility state without an attribute inside it, whether it's referenced or not. I thought I scrubbed the attribute referenced with the visibility state name since the reference is now in the first block, but it won't work unless I leave the attribute inside.

 

Sorry for the long post, but just wanna say thank you again for this thread! One of the most useful things I've found in 6 years of CAD.

 

I have my (messy) code attached:

 

(defun c:test ( / i o s )
   (if (setq s (ssget "_X" '((0 . "INSERT") (66 . 1) (2 . "`*U*,Block1"))))
       (repeat (setq i (sslength s))
           (setq o (vlax-ename->vla-object (ssname s (setq i (1- i)))))
           (if (and (vlax-property-available-p o 'effectivename)
                    (= "block1" (strcase (vla-get-effectivename o) t))
               )
               (progn
                   (princ (strcat "\nFound Block1 block \"" (vla-get-handle o) "\"."))
                   (if (setq v (LM:vl-getattributevalue o "Attribute1"))
                       (progn
                           (princ (strcat "\nValue of \"Attribute1\" attribute = " v))
                           (if (setq s (ssget "_X" '((0 . "INSERT") (66 . 1) (2 . "`*U*,Block2))))
                               (repeat (setq i (sslength s))
                                   (setq o (vlax-ename->vla-object (ssname s (setq i (1- i)))))
                                   (if (and (vlax-property-available-p o 'effectivename)
                                            (= "block2" (strcase (vla-get-effectivename o) t))
                                       )
                                       (progn
                                           (princ (strcat "\nFound Block2 block \"" (vla-get-handle o) "\"."))
                                           (princ)                       
                                           (if (LM:setvisibilitystate o v)
                                               (princ (strcat "\nVisibility state set to \"" v "\"."))
                                               (princ (strcat "\nUnable to set visibility state to \"" v "\"."))
                                           )
                                       )
                                   )
                               )
                              (princ "\nNo attributed 'Block2' blocks found in the drawing.")
                           )
                       )
                       (princ "\n\"Attribute1\" attribute not found in Dbox detail block.")
                  )
               )
           )
       )
       (princ "\nNo attributed 'Block1' blocks found in the drawing.")
   )
   (princ)
)
(vl-load-com) (princ)

;; Get Attribute Value  -  Lee Mac
;; Returns the value held by the specified tag within the supplied block, if present.
;; blk - [vla] VLA Block Reference Object
;; tag - [str] Attribute TagString
;; Returns: [str] Attribute value, else nil if tag is not found.

(defun LM:vl-getattributevalue ( blk tag )
   (setq tag (strcase tag))
   (vl-some '(lambda ( att ) (if (= tag (strcase (vla-get-tagstring att))) (vla-get-textstring att)))
       (vlax-invoke blk 'getattributes)
   )
)

;; Set Attribute Value  -  Lee Mac
;; Sets the value of the first attribute with the given tag found within the block, if present.
;; blk - [vla] VLA Block Reference Object
;; tag - [str] Attribute TagString
;; val - [str] Attribute Value
;; Returns: [str] Attribute value if successful, else nil.

(defun LM:vl-setattributevalue ( blk tag val )
   (setq tag (strcase tag))
   (vl-some
      '(lambda ( att )
           (if (= tag (strcase (vla-get-tagstring att)))
               (progn (vla-put-textstring att val) val)
           )
       )
       (vlax-invoke blk 'getattributes)
   )
)

;; Set Attribute Values  -  Lee Mac
;; Sets attributes with tags found in the association list to their associated values.
;; blk - [vla] VLA Block Reference Object
;; lst - [lst] Association list of ((<tag> . <value>) ... )
;; Returns: nil

(defun LM:vl-setattributevalues ( blk lst / itm )
   (foreach att (vlax-invoke blk 'getattributes)
       (if (setq itm (assoc (vla-get-tagstring att) lst))
           (vla-put-textstring att (cdr itm))
       )
   )
)

;; Get Attributes  -  Lee Mac
;; Returns an association list of attributes present in the supplied block.
;; blk - [vla] VLA Block Reference Object
;; Returns: [lst] Association list of ((<Tag> . <Value>) ... )

(defun LM:vl-getattributes ( blk )
   (mapcar '(lambda ( att ) (cons (vla-get-tagstring att) (vla-get-textstring att)))
       (vlax-invoke blk 'getattributes)
   )
)

;; Get Dynamic Block Property Value  -  Lee Mac
;; Returns the value of a Dynamic Block property (if present)
;; blk - [vla] VLA Dynamic Block Reference object
;; prp - [str] Dynamic Block property name (case-insensitive)

(defun LM:getdynpropvalue ( blk prp )
   (setq prp (strcase prp))
   (vl-some '(lambda ( x ) (if (= prp (strcase (vla-get-propertyname x))) (vlax-get x 'value)))
       (vlax-invoke blk 'getdynamicblockproperties)
   )
)

;; Set Dynamic Block Property Value  -  Lee Mac
;; Modifies the value of a Dynamic Block property (if present)
;; blk - [vla] VLA Dynamic Block Reference object
;; prp - [str] Dynamic Block property name (case-insensitive)
;; val - [any] New value for property
;; Returns: [any] New value if successful, else nil

(defun LM:setdynpropvalue ( blk prp val )
   (setq prp (strcase prp))
   (vl-some
      '(lambda ( x )
           (if (= prp (strcase (vla-get-propertyname x)))
               (progn
                   (vla-put-value x (vlax-make-variant val (vlax-variant-type (vla-get-value x))))
                   (cond (val) (t))
               )
           )
       )
       (vlax-invoke blk 'getdynamicblockproperties)
   )
)


;; Get Dynamic Block Properties  -  Lee Mac
;; Returns an association list of Dynamic Block properties & values.
;; blk - [vla] VLA Dynamic Block Reference object
;; Returns: [lst] Association list of ((<prop> . <value>) ... )

(defun LM:getdynprops ( blk )
   (mapcar '(lambda ( x ) (cons (vla-get-propertyname x) (vlax-get x 'value)))
       (vlax-invoke blk 'getdynamicblockproperties)
   )
)

;; Set Dynamic Block Properties  -  Lee Mac
;; Modifies values of Dynamic Block properties using a supplied association list.
;; blk - [vla] VLA Dynamic Block Reference object
;; lst - [lst] Association list of ((<Property> . <Value>) ... )
;; Returns: nil

(defun LM:setdynprops ( blk lst / itm )
   (setq lst (mapcar '(lambda ( x ) (cons (strcase (car x)) (cdr x))) lst))
   (foreach x (vlax-invoke blk 'getdynamicblockproperties)
       (if (setq itm (assoc (strcase (vla-get-propertyname x)) lst))
           (vla-put-value x (vlax-make-variant (cdr itm) (vlax-variant-type (vla-get-value x))))
       )
   )
)

;; Get Dynamic Block Property Allowed Values  -  Lee Mac
;; Returns the allowed values for a specific Dynamic Block property.
;; blk - [vla] VLA Dynamic Block Reference object
;; prp - [str] Dynamic Block property name (case-insensitive)
;; Returns: [lst] List of allowed values for property, else nil if no restrictions

(defun LM:getdynpropallowedvalues ( blk prp )
   (setq prp (strcase prp))
   (vl-some '(lambda ( x ) (if (= prp (strcase (vla-get-propertyname x))) (vlax-get x 'allowedvalues)))
       (vlax-invoke blk 'getdynamicblockproperties)
   )
)

;; Toggle Dynamic Block Flip State  -  Lee Mac
;; Toggles the Flip parameter if present in a supplied Dynamic Block.
;; blk - [vla] VLA Dynamic Block Reference object
;; Return: [int] New Flip Parameter value

(defun LM:toggleflipstate ( blk )
   (vl-some
      '(lambda ( prp / rtn )
           (if (equal '(0 1) (vlax-get prp 'allowedvalues))
               (progn
                   (vla-put-value prp (vlax-make-variant (setq rtn (- 1 (vlax-get prp 'value))) vlax-vbinteger))
                   rtn
               )
           )
       )
       (vlax-invoke blk 'getdynamicblockproperties)
   )
)

;; Get Visibility Parameter Name  -  Lee Mac
;; Returns the name of the Visibility Parameter of a Dynamic Block (if present)
;; blk - [vla] VLA Dynamic Block Reference object
;; Returns: [str] Name of Visibility Parameter, else nil

(defun LM:getvisibilityparametername ( blk / vis )  
   (if
       (and
           (vlax-property-available-p blk 'effectivename)
           (setq blk
               (vla-item
                   (vla-get-blocks (vla-get-document blk))
                   (vla-get-effectivename blk)
               )
           )
           (= :vlax-true (vla-get-isdynamicblock blk))
           (= :vlax-true (vla-get-hasextensiondictionary blk))
           (setq vis
               (vl-some
                  '(lambda ( pair )
                       (if
                           (and
                               (= 360 (car pair))
                               (= "BLOCKVISIBILITYPARAMETER" (cdr (assoc 0 (entget (cdr pair)))))
                           )
                           (cdr pair)
                       )
                   )
                   (dictsearch
                       (vlax-vla-object->ename (vla-getextensiondictionary blk))
                       "ACAD_ENHANCEDBLOCK"
                   )
               )
           )
       )
       (cdr (assoc 301 (entget vis)))
   )
)

;; Get Dynamic Block Visibility State  -  Lee Mac
;; Returns the value of the Visibility Parameter of a Dynamic Block (if present)
;; blk - [vla] VLA Dynamic Block Reference object
;; Returns: [str] Value of Visibility Parameter, else nil

(defun LM:getvisibilitystate ( blk )
   (LM:getdynpropvalue blk (LM:getvisibilityparametername blk))
)

;; Set Dynamic Block Visibility State  -  Lee Mac
;; Sets the Visibility Parameter of a Dynamic Block (if present) to a specific value (if allowed)
;; blk - [vla] VLA Dynamic Block Reference object
;; val - [str] Visibility State Parameter value
;; Returns: [str] New value of Visibility Parameter, else nil

(defun LM:SetVisibilityState ( blk val / vis )
   (if
       (and
           (setq vis (LM:getvisibilityparametername blk))
           (member (strcase val) (mapcar 'strcase (LM:getdynpropallowedvalues blk vis)))
       )
       (LM:setdynpropvalue blk vis val)
   )
)

 

Edited by xmarcs
Link to comment
Share on other sites

I know I can call two different LISPS with another LISP, so I have gotten it to function with the code at the bottom here. Just seems a bit inefficient as I build this system out with more and more code and referenced blocks. Perhaps this is not the obstacle I thought it was though, since it seems pretty snappy still, as I have added more and more blocks into the system. Any improvements or suggestions would be very much appreciated, but by changing "C:Test" in the above code to "C:Code1" and referencing it with the following LISP, I at least have this functioning relatively smoothly for now. Thanks again so much!

 

(defun c:Master ()
 (C:Code1)
 (C:Code2)
 (princ)
)

 

Link to comment
Share on other sites

Not a solution but a suggestion you can load Lee's dynamic block lisp on demand so dont need to have it live in your code, handy if doing multiple lisps with dynamic blocks.

 

(if (not LM:vl-getattributevalue)(load "Lee-mac-dynamic-block functions.lsp"))

 

Could save each one seperately and only load the function required for the task.

Link to comment
Share on other sites

Nice! That is not something I've considered. I will definitely try to do that when I have my final folder of LISPs to package up for AutoCAD. That makes a lot of sense. Starting to understand how easy it is to reference other LISPs. Very cool. I'll try to strip some of that down along the way and load those separately. Definitely a focus I'll try to read up on in the near future as I build this out. Thanks so much!

Link to comment
Share on other sites

This is using my library routine Multi Radio Buttons.lsp, the main routine reads the visibility states of the block uisng Lee's code then they are displayed, it will accept up to about 20 states. If you post a block will see what I can do.

 

image.png.06881e2cb19d87990db489266527d0d2.png

  • Like 1
Link to comment
Share on other sites

Hi @xmarcs and welcome to CADTutor - I'm delighted that you could fine my code (and this thread) useful.

 

In response to the point you raise regarding attributed blocks:

 

On 5/14/2021 at 3:33 PM, xmarcs said:

Also is there any reason the blocks have to have an attribute? Racked my brain for why the block won't change visibility state without an attribute inside it, whether it's referenced or not. I thought I scrubbed the attribute referenced with the visibility state name since the reference is now in the first block, but it won't work unless I leave the attribute inside.

 

The reason that the code will presently only operate on attributed blocks is due to the presence of DXF group 66 in the ssget filter list; an entry of (66 . 1) in the DXF data of an INSERT entity indicates that ATTRIB entities follow the INSERT in the drawing database, i.e. the block is attributed.

 

For your task, assuming I have understood correctly, I would suggest the following function, accepting three arguments:

 

(defun vsfromatt ( src-blk src-tag tgt-blk / e i n o s v x )
    (if
        (setq s
            (ssget "_X"
                (list
                   '(000 . "INSERT")
                   '(-04 . "<OR")
                       '(-04 . "<AND")
                           '(066 . 1)
                            (cons 002 (strcat "`*U*," src-blk))
                       '(-04 . "AND>")
                        (cons 002 (strcat "`*U*," tgt-blk))
                   '(-04 . "OR>")
                )
            )
        )
        (progn
            (setq i -1)
            (while (and (setq e (ssname s (setq i (1+ i)))) (not (and x v)))
                (setq o (vlax-ename->vla-object e)
                      n (strcase (vlax-get-property o (if (vlax-property-available-p o 'effectivename) 'effectivename 'name)))
                )
                (cond
                    (   (and (null v) (= n (strcase src-blk)))
                        (princ (strcat "\nFound source block \"" src-blk "\" with handle \"" (vla-get-handle o) "\"."))
                        (if (setq v (LM:vl-getattributevalue o src-tag))
                            (princ (strcat "\nFound attribute with tag \"" src-tag "\" and value \"" v "\"."))
                            (princ (strcat "\nAttribute with tag \"" src-tag "\" not found in block \"" src-blk "\"."))
                        )
                    )
                    (   (and (null x) (= n (strcase tgt-blk)))
                        (princ (strcat "\nFound target block \"" tgt-blk "\" with handle \"" (vla-get-handle o) "\"."))
                        (setq x o)
                    )
                )
            )
            (cond
                (   (null v)
                    (princ (strcat "\nNo attributed blocks with name \"" src-blk "\" containing attribute \"" src-tag "\" were found."))
                )
                (   (null x)
                    (princ (strcat "\nNo dynamic blocks with name \"" tgt-blk "\" were found."))
                )
                (   (null (LM:setvisibilitystate x v))
                    (princ (strcat "\nUnable to set visibility state of block \"" tgt-blk "\" to \"" v "\"."))
                )
                (   (princ (strcat "\nVisibility state of block \"" tgt-blk "\" set to \"" v "\".")))
            )
        )
        (princ (strcat "\nNo references of either block \"" src-blk "\" or \"" tgt-blk "\" found in the active drawing."))
    )
    (princ)
)
(vl-load-com) (princ)

 

The above references several of my Dynamic Block Functions and Attribute Functions which you may download from my site, or earlier in this thread to support the operation of the above function.

 

To evaluate the above function, you would define a basic program such as the following:

 

(defun c:test ( )
    (vsfromatt "AttributedBlock1" "AttributeTag1" "DynamicBlock2")
)

 

In this way, you can operate on multiple blocks with difference names & attribute tags by simply evaluating the function with different arguments.

 

This function assumes that you have a single reference of the attributed block & dynamic block (else, how would the program know which attribute value to use with which dynamic block reference), and the program incorporates several efficiency improvements:

  • Rather than nested loops iterating over the set of attributed blocks and then the set of dynamic blocks, this function uses a single loop to iterate over a set containing both references and branches the operation depending on the block reference encountered.
     
  • As soon as the function has acquired both the attribute value and target dynamic block, the function will exit the loop and attempt to set the dynamic block visibility state, with no additional iterations.
  • Like 1
Link to comment
Share on other sites

Lee Mac, you are brilliant, my friend. Thank you so very much for your time. I'm going to start digging into this over the week in between drafting jobs, and will get back to you once I implement, but just wanted to let you know I sent you a small token of my appreciation to the paypal link on your website. I'm just a technician, so it's not much, but can't tell you enough how much I appreciate all your assistance with this kind of stuff. Can't tell you how many times I've seen your name pop up when someone is going through a similar issue that solved so many of my problems. I've learned so much from you and I'll make sure to bookmark your donation site for when I finally get my degree and have a few bucks in my pocket. Thanks for being a real inspiration and a constant source of info. It would not be an exaggeration to say that your website and tutorials are one of the largest reasons I'm going back to engineering school at night. You've opened up so many possibilities for what my daily work day is and can't overstate that. Sorry for the long and off-subject post, but wanted to let you know how awesome you are! Much appreciated, dude.

Link to comment
Share on other sites

That was way easier to wrap my head around than I thought it would be. You're a legend. All I had to do was drop your code in, append another line of blocks and attributes to the test function, and it's now changing several block visibility states at once. Such a game changer being able to import everything from excel without dealing with the block name changing to the number. Found out today that there's really no limit to the number of visibility states you can put in a dyn block too, so very excited to build this out. Cannot thank you enough, Lee!!!

Link to comment
Share on other sites

Thank you for your incredibly kind words @xmarcs, I really appreciate your gratitude for my contributions, and I'm truly delighted to have provided some inspiration for you to continue your engineering studies.

 

I'm pleased that the code was comprehensible and that you could easily make use of it in your program - I hope it allows you to accomplish your goal and automate your processes.

 

Feel free to ask any questions if you are unsure of any area of the code and I'll be happy to explain in more detail.

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...