PDA

View Full Version : Change Layer State with Layout Tab


ccowgill
2006-03-13, 11:31 AM
I am trying to write a lisp routine that will allow us to set a layer state for each layout tab, and let you know if it is running in the background, or give you an option similar to VISRETAIN. We currently have a program called loswitch.dvb which is a protected vba routine, I think it was downloaded from dotsoft. I dont like it, only one person in our office seems to use it and he is the CAD manager. If you dont realize that there are different layer states setup and you make layer changes, it resets them (very annoying) That is why I decided to write a lisp routine that would make you aware that there are layer states present that will affect the layers when you change tabs.

Below is what I have so far, I dont know how to access layer states in the current drawing to see if the program needs to run.


;|
layout switch (c)2006 Chris Cowgill
to replace loswitch.dvb because it acts like visretain is set to 0
|;
(defun c:loswitch ()
(vl-load-com)
(setq App (vlax-Get-Acad-Object)
Doc (vla-Get-ActiveDocument App)
lstate (vla-GetXRecordData layerstate doc)
)
(if (= lstate "model")
(progn
(setq result (dwpMsgbox
"Warning"
"Layer states exist that will result in changes"
"to layer settings when changing layouts"
"Do you wish to use Loswitch?"
vlax-vbOKCancel
vlax-vbExclamation
)
)
(while (= result 1)
(progn
(setq layout (getvar "ctab"))
(if (= layout lstate)
(vla-restore layerstate layout)
(vla-restore layerstate "model")
)
)
)
(dwpMsgbox "Cancel"
"loswitch will not be used"
vlax-vbOKOnly
vlax-vbInformation
)
)
)
)


A basic summary of what I need it to do is this: When a drawing first opens check to see if there is a layer state called model, if there is not, the program does not run, or is set up in the background in case layer states are created, If there is a layer state called model, it displays a dialog letting you know that there are layer states that will affect the drawing, if you hit ok it runs the program, if you hit cancel, it displays a message that loswitch will not be used and then exits the program.

Any help would be greatly appreciated,

CAB2k
2006-03-13, 04:46 PM
Look here (http://www.theswamp.org/index.php?topic=5282.0) for some more ideas.

ccowgill
2006-03-13, 04:48 PM
I get an error message when I go to that site that says the board is either missing or off limits to me

CAB2k
2006-03-13, 05:02 PM
I apologize, I forgot that the forum is restricted to members only.
I would post the code here if it were mine but I only made contributions to the code.

Maybe this will help http://www.doggarncad.com/

ccowgill
2006-03-13, 05:52 PM
I think I could figure it out if I could just figure out how to access layerstates from lisp using vla commands

wayland
2006-03-14, 12:11 AM
Hope you can use the following code, wayland

;; **defun get-LayerStates**
;; This function returns a list of Layer States, if any,
;; in the drawing; it returns 'nil', if there are none.
;; "get-LayerStates" was copied, as "get-statenames"
;; from the AutoDesk VisualLisp and AutoLisp Discussion Group.
;; The author is Luis Esquivel.
;; Function name modified on 07/28/2005,
(defun get-LayerStates (/ collection names)
(if (not
(vl-catch-all-error-p
(setq collection
(vl-catch-all-apply
(function
(lambda ()
(vla-item
(vla-getextensiondictionary
(vla-get-layers
(vla-get-activedocument
(vlax-get-acad-object)
) ; vla-get-activedocument
) ; vla-get-layers
) ; vla-getextensiondictionary
"ACAD_LAYERSTATES"
) ; vla-item
) ; lambda
) ; function
) ; vl-catch-all-apply
) ; setq collection
) ; vl-catch-all-error-p
) ; not
(vlax-for item collection
(setq names
(cons (strcase (vla-get-name item)) names)
) ; setq
) ; vlax-for
) ; if
) ; defun get-LayerStates

;; **defun StateExists**
;; This function is dependent on the function "get-layerstates".
;; This function returns 'T' if a named state is found, it
;; returns 'nil' if it is not found.
;; Author: Wayland Fowler (Taylor & Hill), 07/28/2005
(defun StateExists (state / StateList n ret)
(setq ret nil)
(setq StateList (get-layerstates))
(foreach n StateList
(cond
((= ret T) (setq ret T))
((or (= n (strcase state)) (= n (strcase state T)))
(setq ret T)
) ; a true condition
((and (/= n (strcase state)) (/= n (strcase state T)))
(if (/= ret T)
(setq ret nil)
)
) ; a false condition
) ; cond
) ; end foreach
) ; end defun StateExists[ Moderator Action = ON ] What are [ CODE ] tags... (http://forums.augi.com/misc.php?do=bbcode#code) [ Moderator Action = OFF ]

ccowgill
2006-03-14, 01:00 PM
Ok, obviously I need more help than I thought, I have AutoCAD now able to determine if the specific layers are in the drawing, but I dont know how to get the program to run continuously in the background. I want to be able to go about working and if I switch layout tabs, AutoCAD will change the layerstate. When I run the command if I click OK at the first warning message, AutoCAD hangs until I hit escape.

How do I get the command to fire only when the layout is changed? I know about the Layoutswitched reactor, I just dont know how to use it.

03xtreme
2006-03-21, 02:38 PM
does what you want with readme.

ccowgill
2006-10-09, 09:12 PM
I am working on this program again, now that I have learned how to use reactors. I have run into a road block, I would like my program to only run if a layer state has already been created. The way it runs now is unacceptable as well, in that when the layer states manager is checked manually, there are no saved layer states, yet the program seems to be able to restore them. There also has to be an object drawn in the drawing for it to start working.


;|
Layout Layer Switch
to replace loswitch.dvb because it acts like visretain is set to 0
|;
(vl-load-com)
(if (not My_Layout_End_Reactor)
(setq My_Layout_End_Reactor
(vlr-command-reactor
nil
'((:vlr-commandEnded
.
My_Layout_Ending_Command
) ;end dotted pair
) ;end list
) ;end vl-command-reactor
) ;end setq
() ;The reactor is already loaded
) ;end if
(if (not My_Layer_End_Reactor)
(setq My_Layer_End_Reactor
(vlr-command-reactor
nil
'((:vlr-commandEnded
.
My_Layer_Ending_Command
) ;end dotted pair
) ;end list
) ;end vlr-command-reactor
) ;end setq
() ;The reactor is already loaded
) ;end if
;;; Function used as Callbacks when the event fires / reactor triggers
(defun My_Layout_Ending_Command (In_ReactorName In_Command /)
(if
(= (car In_Command) "LAYOUT_CONTROL")
(restore-layerstate (getvar "ctab"))
() ;The last command was not Layout_control
) ;end if
(princ)
) ;end defun
;;; Function used as Callbacks when the event fires / reactor triggers
(defun My_Layer_Ending_Command (In_ReactorName In_Command /)
(if
(= (car In_Command) "LAYER")
(set-layerstate (getvar "ctab") aclsall)
() ;The last command was not Layer
) ;end if
(princ)
) ;end defun
(defun get-acadobject ()
(setq *acad*
(cond
(*acad*)
((vlax-get-acad-object))
(T nil)
)
)
)
(defun get-activedocument ()
(setq *doc*
(cond
(*doc*)
((vla-get-activedocument (get-acadobject)))
(T nil)
)
)
)
(defun delete-layerstate (obj name)
(if (vl-catch-all-error-p
(vl-catch-all-apply
'vla-delete
(list obj name)
)
)
nil
T
)
)
(defun save-layerstate (obj name mask)
(if (vl-catch-all-error-p
(vl-catch-all-apply
'vla-save
(list obj name mask)
)
)
nil
T
)
)
(defun set-layerstate (name mask)
(setq state
(vlax-create-object
"AutoCAD.AcadLayerStateManager.16"
)
)
(vla-setdatabase
state
(vla-get-database (get-activedocument))
)
(delete-layerstate state name)
(save-layerstate
state
name
;; acLsAll
mask
)
)
(defun get-statenames (/ collection names)
(if (not
(vl-catch-all-error-p
(setq collection
(vl-catch-all-apply
(function (lambda ()
(vla-item (vla-getextensiondictionary
(vla-get-layers
(get-activedocument)
)
)
"ACAD_LAYERSTATES"
)
)
)
)
)
)
)
(vlax-for item collection
(setq names (cons (strcase (vla-get-name item)) names))
)
)
)
(defun restore-layerstate (name)
(if (and state
(vl-position
(strcase name)
(get-statenames)
)
)
(progn (vla-restore state name)
(delete-layerstate state name)
(vlax-release-object state)
(setq state nil)
)
)
)
;; (get-layerstate "TEST")
(defun get-layerstate (name)
(if (vl-position
(strcase name)
(get-statenames)
)
name
)
)


any help would be appreciated.

charlesjueb
2006-10-09, 09:56 PM
hey, what does this zip file do?

ccowgill
2006-10-09, 10:05 PM
hey, what does this zip file do?
not what I am looking for, It automatically changes layer states even if you forget to save them. The routine I am using uses reactors to automatically save changes to layer states when the layer command is completed. In my mind, it takes care of the "VISRETAIN" issue. The lisp routine included in the zip uses command, which from what I understand, you cant do with reactors

charlesjueb
2006-10-09, 10:31 PM
ok. i have also been wanting to be able to change the layer state in coordination with the layout tab. there seems to be no easy way. is this something that autocad 2007 has available?

thanks!

ccowgill
2006-10-09, 10:35 PM
ok. i have also been wanting to be able to change the layer state in coordination with the layout tab. there seems to be no easy way. is this something that autocad 2007 has available?

thanks!
I am still on 05, if it is something that 07 offers, I can stop wasting my time because we are upgrading in 2 weeks.

Because it is not something, as far as I know, that has come out yet (or at least what is out there doesn't do what I need it to do), I am trying to create it myself. I have just run into a snag.

charlesjueb
2006-10-09, 10:39 PM
Well i don't think i can be of much help, but keep me posted if you figure it out.

thanks.

03xtreme
2006-10-10, 02:53 PM
CO

i have the same issue with SSD, it changes the layerstate without you knowing. Even worse, it won't change the layerstate BEFORE you make a plot when using publish. Not only do you need it to save per layout, you need it to react prior to the plotting event. I don't even use that anymore because the stupid thing reacts after you publish the layout which is... well... useless in my mind.

I'm extremely interested in this and it sounds like you are very close.

ccowgill
2006-10-10, 07:39 PM
You can use my program to create a reactor that sets the layout tab current when the drawing is opened. I am not sure how publish reacts to commands in progress. I have publish in the foreground, so I would think that the open command would cause the reactor to fire before the publish command does its job.

The problem still is, when my program creates the layerstate, it doesn't show up in the layerstates manager. It is still there because I have another program designed to detect when LOSWITCH is being used (detects if a layerstate called model exists).

My program needs an if statement to be checked each time the reactor fires before it restores or saves the layerstate. I need to check to see if there are any layerstates in the drawing that match any of the layout tab names. If there is even one match, then it would restore or save the layerstate that corresponds to that tab. I also need the layerstate names to show up in the manager.

I have two pictures attached, LOSWITCH is the message that shows up when there is a layer state called model, and LAYERSTATES is the view of the layerstates in that drawing (hopefully this will clear up what I am saying about the name not showing up.)

03xtreme
2006-10-10, 07:45 PM
so it is making the layer state but not displaying it in the dialogue box

i have definitely found that loswitch reacts after, because it appears autocad switches tabs plots the model space view port then paperspace then the reactor causes the layers to switch then it goes to the next layout tab. really we need loswitch to occure before model space is printed.

ccowgill
2006-10-10, 07:56 PM
so it is making the layer state but not displaying it in the dialogue box
That is correct, I need my program to work as closely as possible to LOSWITCH.dvb, but give a user that has no clue it is running a fighting chance. At our office, I think it is pretty safe to say only the cad supervisor uses the program. Since he is the boss, and I really dont like the command, I need to replace it without making it look too different. Even though he is the boss, I pretty much get free reign as to the programs and routines that we run, as long as it doesnt change significantly, something he uses.


i have definitely found that loswitch reacts after, because it appears autocad switches tabs plots the model space view port then paperspace then the reactor causes the layers to switch then it goes to the next layout tab. really we need loswitch to occure before model space is printed.
the only thing you can do is change the command sequence, you can change try it as is and see if that works, then change ended to willstart and see if that works, but with getvar "ctab", it might still grab the previous tab's layer state. There are also a few other reactors that can be tried.

03xtreme
2006-10-10, 08:39 PM
change it in your code right, because i don't think the vba for loswitch is hackable, it is protected i believe.

does yours fix the reactor issue i mention?

ccowgill
2006-10-10, 08:43 PM
I couldn't tell you right now, I would like to get the layerstate names to show up first, then it will be easier to determine whether or not it is switching layerstates.

ccowgill
2006-10-17, 12:58 PM
Here is my code, it works perfectly fine. The layerstate names created do NOT show up in the Layerstates Manager. That is my problem, could someone please help me figure out how to get the names to show up in the Layerstates Manager Dialog box?


;|
Layout Layer Switch
to replace loswitch.dvb because it acts like visretain is set to 0
|;
(vl-load-com)
(if (not My_Layout_End_Reactor)
(setq My_Layout_End_Reactor
(vlr-command-reactor
nil
'((:vlr-commandEnded
.
My_Layout_Ending_Command
) ;end dotted pair
) ;end list
) ;end vl-command-reactor
) ;end setq
() ;The reactor is already loaded
) ;end if
(if (not My_Layer_End_Reactor)
(setq My_Layer_End_Reactor
(vlr-command-reactor
nil
'((:vlr-commandEnded
.
My_Layer_Ending_Command
) ;end dotted pair
) ;end list
) ;end vlr-command-reactor
) ;end setq
() ;The reactor is already loaded
) ;end if
;;; Function used as Callbacks when the event fires / reactor triggers
(defun My_Layout_Ending_Command (In_ReactorName In_Command /)
(if
(= (car In_Command) "LAYOUT_CONTROL")
(restore-layerstate (getvar "ctab"))
() ;The last command was not Layout_control
) ;end if
(princ)
) ;end defun
;;; Function used as Callbacks when the event fires / reactor triggers
(defun My_Layer_Ending_Command (In_ReactorName In_Command /)
(if
(= (car In_Command) "LAYER")
(set-layerstate (getvar "ctab") aclsall)
() ;The last command was not Layer
) ;end if
(princ)
) ;end defun
(defun get-acadobject ()
(setq *acad*
(cond
(*acad*)
((vlax-get-acad-object))
(T nil)
)
)
)
(defun get-activedocument ()
(setq *doc*
(cond
(*doc*)
((vla-get-activedocument (get-acadobject)))
(T nil)
)
)
)
(defun delete-layerstate (obj name)
(if (vl-catch-all-error-p
(vl-catch-all-apply
'vla-delete
(list obj name)
)
)
nil
T
)
)
(defun save-layerstate (obj name mask)
(if (vl-catch-all-error-p
(vl-catch-all-apply
'vla-save
(list obj name mask)
)
)
nil
T
)
)
(defun set-layerstate (name mask)
(setq state
(vlax-create-object
"AutoCAD.AcadLayerStateManager.16"
)
)
(vla-setdatabase
state
(vla-get-database (get-activedocument))
)
(delete-layerstate state name)
(save-layerstate
state
name
;; acLsAll
mask
)
)
(defun get-statenames (/ collection names)
(if (not
(vl-catch-all-error-p
(setq collection
(vl-catch-all-apply
(function (lambda ()
(vla-item (vla-getextensiondictionary
(vla-get-layers
(get-activedocument)
)
)
"ACAD_LAYERSTATES"
)
)
)
)
)
)
)
(vlax-for item collection
(setq names (cons (strcase (vla-get-name item)) names))
)
)
)
(defun restore-layerstate (name)
(if (and state
(vl-position
(strcase name)
(get-statenames)
)
)
(progn (vla-restore state name)
(delete-layerstate state name)
(vlax-release-object state)
(setq state nil)
)
)
)
;; (get-layerstate "TEST")
(defun get-layerstate (name)
(if (vl-position
(strcase name)
(get-statenames)
)
name
)
)



by adding this reactor, the program will also check the layerstate when a drawing is first opened, I believe this will cause it to change layerstates if necessary before the publish command plots the drawing.


:vlr-endDwgOpen


Thank you,