Get Selected Element's Layer Name

Get Selected Element's Layer Name

ebsoares
Collaborator Collaborator
4,586 Views
13 Replies
Message 1 of 14

Get Selected Element's Layer Name

ebsoares
Collaborator
Collaborator

Hi, all.

 

I was wondering if someone could help me finish this routine.

 

Basically, it needs to figure out if the user has something selected - this part works.

  • If there's nothing selected, do something ("doThis") - this part works, too.
  • If there's something selected, we need to do something else ("doThat"), but use the selected element's layer just for this one task, then get back to the previous layer.

The routine gives an error when it reaches the 6th line, where it should be setting the new variable newLayer to the object's layer name - I haven't been able to have it figure out what the selected object's layer name is.

 

One more thing, to make it more robust, if there's more than one object selected, is there a way to have the routine just ignore all of the elements but, say, the last one on the selection list?

 

I'd appreciate any help, even finding a new approach to the way this should work altogether.

 

Here's the code I have so far:

 

(defun C:Work ()
    (if (not (setq mySS (ssget "_I"))) ; create sset if there's anything selected
        (doThis) ; action if there's nothing selected
        (progn ; action if selection exists
            (setq oldLayer (getvar "CLAYER")) ; saves current layer
            (setq newLayer (cdr (assoc 8 (entget mySS)))) ; get selection's layer
            (setvar "CLAYER" newLayer) ; make that layer current
            (doThat) ; work on this new layer
            (setvar "CLAYER" oldLayer) ; restores previous layer
        )
    )
    (setq mySS nil) ; empties selection (is this good practice, or do we not need to do it?)
    (princ)
)

 

BTW, I found these posts, but still haven't been able to solve it...

 

Again, thanks in advance.

 

Edgar

0 Likes
Accepted solutions (2)
4,587 Views
13 Replies
Replies (13)
Message 2 of 14

john.uhden
Mentor
Mentor

Using ssget can return a selection set of multiple objects.  Then you are trying to use entget on a selecton set.  Entget can be used only on an entity name.

Presuming you want to select only one entity (to get its layer name), then I recommend you use entsel instead.

I modified your code to show what you might be trying to do...

 

(defun C:Work ( / E Oldlayer Newlayer)
    (if (not (setq E (car (entsel)))) ; select one object
        (doThis) ; action if there's nothing selected
        (progn ; action if selection exists
            (setq oldLayer (getvar "CLAYER")) ; saves current layer
            (setq newLayer (cdr (assoc 8 (entget E)))) ; get selection's layer
            (setvar "CLAYER" newLayer) ; make that layer current
            (doThat) ; work on this new layer
            (setvar "CLAYER" oldLayer) ; restores previous layer
        )
    )
    ;; The following is not needed since E is declared as a local variable
    ;; (setq mySS nil) ; empties selection (is this good practice, or do we not need to do it?)
    (princ)
)

John F. Uhden

Message 3 of 14

ebsoares
Collaborator
Collaborator

Hi, @john.uhden. Thanks for that! ...but not quite there yet.

 

If I could bother you for a couple of changes...

  • When the user calls "work" it asks to select something - can we just have the routine not ask the user? If there's nothing selected, just go to "doThis" and don't ask for a selection, and if there's an element selected already (prior to the routine run), just "doThat" and don't ask for a selection either.
  • Also, at the end, when the routine runs the line "(setvar "CLAYER" oldLayer)" it actually grabs the object created in "doThat" (I'm placing a symbol in that part) and changes the layer of that object from newLayer to oldLayer... if I comment that line out it works (new object in new layer), but then I'm stuck in the new layer.

Here's the actual routine I'm trying to run (we have a block called "tilde"):

 

; Insert TILDE at 20 scale. Pauses for mouse input
(defun C:TILDE (/ E oldLayer newLayer)
    (if (not (setq E (car (entsel)))) ; entsel allows only one object in selection
        (placeTilde) ; action if there's nothing selected
        (progn ; action if there's something selected
            (setq oldLayer (getvar "CLAYER")) ; saves current layer
            (setq newLayer (cdr (assoc 8 (entget E)))) ; get selection's layer
            (setvar "CLAYER" newLayer) ; make that layer current
            (placeTilde)
            (setvar "CLAYER" oldLayer) ; restores previous layer
        )
    )
    (princ)
)
; 
; Insert tilde:
(defun placeTilde ()
    (command "-INSERT" "TILDE" PAUSE "20" )
)

Thanks again for any extra time you put into this, John 🙂

 

Edgar

 

0 Likes
Message 4 of 14

Kent1Cooper
Consultant
Consultant
Accepted solution

@ebsoares wrote:

... can we just have the routine not ask the user? If there's nothing selected, just go to "doThis" and don't ask for a selection, and if there's an element selected already (prior to the routine run), just "doThat" and don't ask for a selection either. .... 


You would also need to account for the possibility of more than one thing already selected, in which case [since you're looking for information that must be from one object] you would need to decide whether to clear that multiple selection and ask the User to select a single thing, or reject the command altogether, or use the first item in the selection, or something.  Try something like this, which does the first of those things:

 

  (defun doThat (); series of things to do if single object selected
(... do one thing ...); [using the 'ent' variable from other parts]
(... do another thing ...)
(... do something else ...)
); doThat (cond ( (and (setq ss (ssget "_I")); something pre-selected (= (sslength ss) 1); only one object ); and (setq ent (ssname ss 0)); use that object, and:
(doThat) ); first condition [single pre-selected object] ( (ssget "_I"); more than one object selected [previous condition not satisfied] (sssetfirst nil); un-select multiple objects     (while (not ent); ask User to select,
      (setq ent (car (entsel "\nSelect one object: ")))
    ); while -- then:
(doThat) ); second condition (T (...do This... [series of things])); [nothing pre-selected] ); cond
Kent Cooper, AIA
Message 5 of 14

ВeekeeCZ
Consultant
Consultant

I would not bother... I would keep it simple.

 

(defun C:TILDE (/ ss)
  (setq ss (ssget "_I"))
  (placeTilde)
  (if ss (command "_.CHPROP" "_Last" "" "_La" (cdr (assoc 8 (entget (ssname ss 0)))) ""))
  (princ)
  )


(defun placetilde ()
  (command "-INSERT" "TILDE" PAUSE "20")
  (while (> (getvar 'CMDACTIVE) 0)
    (command PAUSE))
)
Message 6 of 14

ebsoares
Collaborator
Collaborator

Thanks for the help, Kent! Works perfectly!

 

Still having the issue with not being able to go back to previous layer though:

  • If the routine uses (setvar "CLAYER" oldLayer), it sets the layer of the block it just placed (which was in the correct layer already) to the "oldLayer"
  • I tried using the command "layerp" (commented out in the code below), but the routine to tries to run that line before it finishes the "-INSERT" command running in the placeTilde function...

I think that in both occasions the lisp is trying to run a line of code (the layerp or the clayer one) before it finishes the "-INSERT" command. Could all that be caused by the "pause" in that little function?

 

Here's my code, with your edits:

; Insert TILDE at 20 scale. Pauses for mouse input
(defun C:TILDE (/ ent oldLayer newLayer)
    (cond
        (    (and (setq ss (ssget "_I")); something is pre-selected
                (= (sslength ss) 1); has to be only one object
            ); and
            (setq ent (ssname ss 0)); use that object, and:
            (setq oldLayer (getvar "CLAYER")) ; saves current layer
            (setq newLayer (cdr (assoc 8 (entget ent)))) ; get selection's layer
            (setvar "CLAYER" newLayer) ; make that layer current
            (placeTilde)
            ;(command "layerp" "")
            (setvar "CLAYER" oldLayer) ; make that layer current
        ) ; end condition 1
        (    (ssget "_I"); more than one object selected [previous condition not satisfied]
            (sssetfirst nil); un-select multiple objects
            (while (not ent)
                (setq ent (car (entsel "\nSelect one object: "))
                )
            )
            (setq oldLayer (getvar "CLAYER")) ; saves current layer
            (setq newLayer (cdr (assoc 8 (entget ent)))) ; get selection's layer
            (setvar "CLAYER" newLayer) ; make that layer current
            (placeTilde)
            ;(command "layerp" "")
            (setvar "CLAYER" oldLayer) ; make that layer current
        ) ; end condition 2
        (T ; [nothing pre-selected]
            (placeTilde)
        )
    )
    (princ)
)
; 
; Insert tilde:
(defun placeTilde ()
    (command "-INSERT" "TILDE" PAUSE "20" "20") ; PAUSE is for user to rotate block
)

Thanks again!

 

Edgar

0 Likes
Message 7 of 14

ВeekeeCZ
Consultant
Consultant
(defun placeTilde ()
    (command "-INSERT" "TILDE" PAUSE "20" "20") ; PAUSE is for user to rotate block
)

Why? I may cause issues, because your last (setvar "CLAYER" oldLayer) is happening BEFORE the "Insert" command even finish. Put it inside, or use my way. If you're set the rotation, see what happend with current layer. 

Message 8 of 14

ebsoares
Collaborator
Collaborator

Wow, @ВeekeeCZ! That was great! Thank you very much!

 

Kent and John, thank you, too, for all the help today.

 

Till next time,

 

Edgar

0 Likes
Message 9 of 14

ebsoares
Collaborator
Collaborator

For anyone coming in here, looking for the same thing, here's the final code, combining Kent's and BeekeeCZ's input:

 

; Edgar Soares, Nov 2016
;
; Command: "TILDE"
;
; Places the TILDE block at 20 scale, pausing for mouse input.
; If something's selected, places said block in the selection's layer
;
; In collaboration with (mostly them, actually) @Kent1Cooper and @BeekeeCZ:
;   https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/get-selected-element-s-layer-name/m-p/6666324
;
;
(defun C:TILDE (/ ent oldLayer newLayer)
    (cond
        (    (and (setq ss (ssget "_I")); something is pre-selected
                (= (sslength ss) 1); has to be only one object
            ); and
            (setq ent (ssname ss 0)); use that object, and:
            (placeTilde)
            (if ss
                (command "_.CHPROP" "_Last" "" "_La" (cdr (assoc 8 (entget (ssname ss 0)))) "")
            )
        ) ; end condition 1
        (    (ssget "_I"); more than one object selected [previous condition not satisfied]
            (sssetfirst nil); un-select multiple objects
            (while (not ent)
                (setq ent (car (entsel "\nSelect one object: "))
                )
            )
            (placeTilde)
            (if ss
                (command "_.CHPROP" "_Last" "" "_La" (cdr (assoc 8 (entget (ssname ss 0)))) "")
            )
        ) ; end condition 2
        (T ; [nothing pre-selected]
            (placeTilde)
        )
    )
    (princ)
)
; 
; Insert tilde:
(defun placeTilde ()
    (command "-INSERT" "TILDE" PAUSE "20" "20")
    (while (> (getvar 'CMDACTIVE) 0)
        (command PAUSE)
    )
)
0 Likes
Message 10 of 14

ВeekeeCZ
Consultant
Consultant
Accepted solution

@ebsoares wrote:

For anyone coming in here, looking for the same thing, here's the final code, combining Kent's and BeekeeCZ's input:

 

; Edgar Soares, Nov 2016
;
; Command: "TILDE"
;
; Places the TILDE block at 20 scale, pausing for mouse input.
; If something's selected, places said block in the selection's layer
;
; In collaboration with (mostly them, actually) @Kent1Cooper and @BeekeeCZ:
;   https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/get-selected-element-s-layer-name/m-p/6666324
;
;
(defun C:TILDE (/ ent oldLayer newLayer)
    (cond
        (    (and (setq ss (ssget "_I")); something is pre-selected
                (= (sslength ss) 1); has to be only one object
            ); and
            (setq ent (ssname ss 0)); use that object, and:
            (placeTilde)
            (if ss
                (command "_.CHPROP" "_Last" "" "_La" (cdr (assoc 8 (entget (ssname ss 0)))) "")
            )
        ) ; end condition 1
        (    (ssget "_I"); more than one object selected [previous condition not satisfied]
            (sssetfirst nil); un-select multiple objects
            (while (not ent)
                (setq ent (car (entsel "\nSelect one object: "))
                )
            )
            (placeTilde)
            (if ss
                (command "_.CHPROP" "_Last" "" "_La" (cdr (assoc 8 (entget (ssname ss 0)))) "")
            )
        ) ; end condition 2
        (T ; [nothing pre-selected]
            (placeTilde)
        )
    )
    (princ)
)
; 
; Insert tilde:
(defun placeTilde ()
    (command "-INSERT" "TILDE" PAUSE "20" "20")
    (while (> (getvar 'CMDACTIVE) 0)
        (command PAUSE)
    )
)

Unfortunatelly the red part is wrong because of the blue part.
And generally is not a good practice do the same thing on multiple places if that is not necessaty. I've shown you the principle before -- take a challenge and do the layer change on just single place on your own. Then you can see the spoiler 🙂

 

Spoiler
(defun C:TILDE (/ ent ss)
   
  (cond
    (    (and (setq ss (ssget "_I")); something is pre-selected
	      (= (sslength ss) 1); has to be only one object
	      ); and
     (setq ent (ssname ss 0)) ; use that object, and:
     ) ; end condition 1
    
    (    (ssget "_I"); more than one object selected [previous condition not satisfied]
     (sssetfirst nil); un-select multiple objects
     (while (not ent)
       (setq ent (car (entsel "\nSelect one object: "))))
     ) ; end condition 2
    )
  (placeTilde)
  (if ent (command "_.CHPROP" "_Last" "" "_La" (cdr (assoc 8 (entget ent))) ""))
  (princ)
  )


; Insert tilde:
(defun placeTilde ()
  (command "-INSERT" "TILDE" PAUSE "20" "20")
  (while (> (getvar 'CMDACTIVE) 0)
    (command PAUSE)
    )
  )
Message 11 of 14

ebsoares
Collaborator
Collaborator

Hummm...

 

Here's my code:

(defun C:TD (/ ent ss oldLayer newLayer)
    (cond
        (    (and (setq ss (ssget "_I")); something is pre-selected
                (= (sslength ss) 1); has to be only one object
            ); and
            (setq ent (ssname ss 0)); use that object, and:
            (placeTilde)
            (tildeLayer ss) ; change layer
        ) ; end condition 1
        (    (ssget "_I"); more than one object selected [previous condition not satisfied]
            (sssetfirst nil); un-select multiple objects
            (while (not ent)
                (setq ent (car (entsel "\nSelect one object: "))
                )
            )
            (placeTilde)
            (tildeLayer ss) ; change layer
        ) ; end condition 2
        (T ; [nothing pre-selected]
            (placeTilde)
        ) ; end final condition
    )
    (princ)
)
; 
; Insert tilde:
(defun placeTilde ()
    (command "-INSERT" "TILDE" PAUSE "20"); "20")
    (while (> (getvar 'CMDACTIVE) 0)
        (command PAUSE)
    )
)
;
; Change layer:
(defun tildeLayer (ss / )
    (if ss ; means "if ss not nil"
        (command "_.CHPROP" "_Last" "" "_La" (cdr (assoc 8 (entget (ssname ss 0)))) "")
    )
)

I couldn't do the way you did because there's still a third condition, where nothing is selected to begin with (the "T" condition), in which case we'd just want to keep the current layer.

I still tried to have the layer change routine in a single spot, like you see above. But like you pointed out, it's not working well during the second condition (it basically uses the layer of the first element in the selection). I tried to pass "(tildeLayer ent)" in the second condition, but it just made things worse (it wanted to create a layer).

That got me...

0 Likes
Message 12 of 14

ВeekeeCZ
Consultant
Consultant

Ok, your code from post #9 fixed. The same thing applies on post #11. 

 

Spoiler
; Edgar Soares, Nov 2016
;
; Command: "TILDE"
;
; Places the TILDE block at 20 scale, pausing for mouse input.
; If something's selected, places said block in the selection's layer
;
; In collaboration with (mostly them, actually) @Kent1Cooper and @BeekeeCZ:
;   https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/get-selected-element-s-layer-name/m-p/6666324
;
;
(defun C:TILDE (/ ent oldLayer newLayer)
    (cond
        (    (and (setq ss (ssget "_I")); something is pre-selected
                (= (sslength ss) 1); has to be only one object
            ); and
            (setq ent (ssname ss 0)); use that object, and:
            (placeTilde)
            (if ss ; cond ss not necessary, but does not hurt.
                (command "_.CHPROP" "_Last" "" "_La" (cdr (assoc 8 (entget (ssname ss 0)))) "")
            )
        ) ; end condition 1
        (    (ssget "_I"); more than one object selected [previous condition not satisfied]
            (sssetfirst nil); un-select multiple objects
            (while (not ent)
                (setq ent (car (entsel "\nSelect one object: "))
                )
            )
            (placeTilde)
            (if ss ; cond ss not necessary, but does not hurt.
                (command "_.CHPROP" "_Last" "" "_La" (cdr (assoc 8 (entget ent))) "")
            )
        ) ; end condition 2
        (T ; [nothing pre-selected]
            (placeTilde)
        )
    )
    (princ)
)
; 
; Insert tilde:
(defun placeTilde ()
    (command "-INSERT" "TILDE" PAUSE "20" "20")
    (while (> (getvar 'CMDACTIVE) 0)
        (command PAUSE)
    )
)

In my code -- spoiler #10 -- IS the third cond covered because of (if ent...) condition. The ent only exists if this was filled in the first or second condition. You can test it and keep it as it is 🙂

 

Have fun and good luck! Cheers!

0 Likes
Message 13 of 14

ebsoares
Collaborator
Collaborator

Hi, BeekeeCZ. Sorry I didn't reply earlier... (I didn't work Friday and this week I've been having issues trying to login here)

 

I went back to your code and, sure enough, it makes total sense now!

 

Quick question - is there a way to unmark my post as the answer? It'll get in the way of other people in the future looking for this (if there's ever any).

 

In any case, thanks a bunch!

 

Edgar

0 Likes
Message 14 of 14

ВeekeeCZ
Consultant
Consultant

@ebsoares wrote:

... 

I went back to your code and, sure enough, it makes total sense now!

 

Quick question - is there a way to unmark my post as the answer? It'll get in the way of other people in the future looking for this (if there's ever any).

 

...

Glad you got it.

 

See the upper-right corner of the post, there are Options, one of them is "Not a Solution"

0 Likes