PDA

View Full Version : How can I recognize when switching between drawings with a reactor?


kennet.sjoberg
2009-03-10, 01:31 PM
I have tried this code with no luck

The test function will never be trigged

(defun Function_When_Switching_Drawing (ObjArg ListArg / )
(alert "Drawing Switched" )
)


The reactor

(setq Switching_Drawing_REACTOR (vlr-docmanager-reactor '((:vlr-documentToBeActivated . Function_When_Switching_Drawing ))) )
(setq Switching_Drawing_REACTOR2 (vlr-docmanager-reactor '((:vlr-documentToBeDeactivated . Function_When_Switching_Drawing ))) )


To remove the reactor and function

(vlr-remove Switching_Drawing_REACTOR )
(setq Function_When_Switching_Drawing nil Switching_Drawing_REACTOR nil )


: ) kennet

Opie
2009-03-10, 02:05 PM
Aren't you missing a part of the reactor call? I thought there were at least two arguments required for reactors.
(setq Switching_Drawing_REACTOR (vlr-docmanager-reactor nil '((:vlr-documentToBeActivated . Function_When_Switching_Drawing ))) )

You also may not want to do both of those reactors. I went into an endless loop and had to close down AutoCAD.

irneb
2009-03-10, 02:20 PM
I generally add some form of identification (instead of nil) to the reactor declaration. That way I don't need a global variable, to hold the reference to the reactor, in order to remove it.

Someting like (vlr-docmanager-reactor "Check DWG Switch" .....).

Then I also add some code just before declaring it, something like:;; Clear reactors
(setq rlst (vlr-reactors))
(foreach item rlst
(foreach ro (cdr item)
(if (= "Check DWG Switch" (vlr-data ro))
(vlr-remove ro)
) ;_ end of if
) ;_ end of foreach
) ;_ end of foreach
Otherwise you may be loading that LSP again & have the reactor firing twice. This is usually the case while debugging, but may also happen if the LSP is loaded in 2 places.

kennet.sjoberg
2009-03-11, 03:38 PM
Yes Opie, the nil argument is missed in the forum ( both lines ), but I misspelled in a different way in my code, sorry for taking your time. Thank you anyway and. . .

: ) Happy Computing !

kennet

ccowgill
2009-08-20, 08:40 PM
Aren't you missing a part of the reactor call? I thought there were at least two arguments required for reactors.
(setq Switching_Drawing_REACTOR (vlr-docmanager-reactor nil '((:vlr-documentToBeActivated . Function_When_Switching_Drawing ))) )
You also may not want to do both of those reactors. I went into an endless loop and had to close down AutoCAD.
I think it goes into an endless loop with only one of the reactors.

I need some assistance that is right up this program's alley. I am trying to add some extra measures to keep Eagle Point (EP) in line (it's our third party civil software) We would like to be able to use MDI (some of us do already) but I dont want the users to necessarily be concerned with making sure they switch between drawings using the Eagle Point interface. I found which registry key is modified when EP switches between drawings, so I figured I would write a lisp that will automatically change the registry key if the user switches to the drawing via AutoCAD (that way EP doesnt freak out.) I have the program written (as far as I know), but I need help on the reactor to get it to run.


(defun epcdchange ()
(if
(and
(or
(wcmatch (strcase (vl-filename-base (getvar "dwgname")))
"RCP#####,RC######,RCPRF###,RCT#####,RCXSC###,SSHY####,STHY####"
) ;_ end of wcmatch
(vl-file-systime (strcat (getvar "dwgprefix") (vl-filename-base (getvar "dwgname")) ".set"))
) ;_ end of or
(= (vl-registry-read
"HKEY_CURRENT_USER\\Software\\Eagle Point Software\\egpt\\EP\\"
"CurrentDataLocation"
) ;_ end of vl-registry-read
(getvar "dwgprefix")
) ;_ end of =
) ;_ end of and
(vl-registry-write
"HKEY_CURRENT_USER\\Software\\Eagle Point Software\\egpt\\EP\\"
"CurrentDrawing"
(strcat (getvar "dwgprefix") (getvar "dwgname"))
) ;_ end of vl-registry-write
) ;_ end of if
) ;_ end of defun



Any suggestions would be appreciated (if you think this is a bad idea please let me know why)

Thanks,

Opie
2009-08-21, 04:42 AM
Christopher,

You probably need two reactors, one for activation and one for deactivation.

For the activation, check to see if a global variable is set. If it is not set, assign it any value then run your code. If it is set, it means you have already run your code so do not run your code again.

For the deactivation, set the global variable to nil. This will allow the activation code to work when you get back in to a EP project drawing.

I'll have to check your code tomorrow (if I have time) to see how it works with EP. I could possibly use this as well.

ccowgill
2009-08-21, 02:23 PM
Christopher,

You probably need two reactors, one for activation and one for deactivation.

For the activation, check to see if a global variable is set. If it is not set, assign it any value then run your code. If it is set, it means you have already run your code so do not run your code again.

For the deactivation, set the global variable to nil. This will allow the activation code to work when you get back in to a EP project drawing.

I'll have to check your code tomorrow (if I have time) to see how it works with EP. I could possibly use this as well.
It is way too early in the morning, I dont have a clue what you are referring to. Any chance you can provide an example? I tried using the tobeactivated reactor and it seemed to throw AutoCAD into an infinite loop. Then I tried a documentbecamecurrent reactor, but it appears to be firing multiple times and I dont have a clue how to get around it.

Opie
2009-08-21, 03:18 PM
In your routine that is called based on the reactor for activation (renamed here from epcdchange), add an if statement

(defun WJ:EPToBeActivated (ObjArg ListArg) ;To use in a reactor, you need two arguments added to your code
(if (not blnFlag)
(progn
(setq blnFlag t)
Do the rest of your command...
)
)
)

Create another routine for the deactivation

(defun WJ:EPToBeDeactivated (ObjArg ListArg)
(if blnFlag
(setq blnFlag nil)
)
)

Then add your reactor for activation
(vlr-docmanager-reactor
"WJ:EPToBeActivated"
'((:vlr-documentToBeActivated . WJ:EPToBeActivated))
)

And one for deactivation
(vlr-docmanager-reactor
"WJ:EPToBeDeactivated"
'((:vlr-documentToBeDeactivated . WJ:EPToBeDeactivated))
)

And using irneb's code for removal of the reactors
(setq rlst (vlr-reactors))
(foreach item rlst
(foreach ro (cdr item)
(if (member (vlr-data ro) '("WJ:EPToBeActivated" "WJ:EPToBeActivated"))
(vlr-remove ro)
)
)
)

ccowgill
2009-08-21, 03:23 PM
ok, rewording it the way I understand it, Create a reactor that fires when the drawing becomes activated, the program will have a flag that will only allow it to run once, even if the reactor fires multiple times. Then when the drawing is deactivated, it will reset the flag to nil so that the next time the drawing is activated the program will run once. correct?
We house all of our reactor's in the same file, and they call to other functions, that way it reduces the likelihood that a reactor will be loaded more than once. Here is what I have for a portion of my reactor file:

(if (not Activating_Drawing_Reactor)
(setq Activating_Drawing_Reactor
(vlr-docmanager-reactor
"WJ:EPToBeActivated"
'((:vlr-documenttobeactivated
.
WJ:EPToBeActivated
)
)
) ;_ end of vlr-docmanager-reactor
) ;_ end of setq
() ;_ the reactor is already loaded
) ;_ end of if
(if (not Deactivating_Drawing_Reactor)
(setq Deactivating_Drawing_Reactor
(vlr-docmanager-reactor
"WJ:EPToBeDeactivated"
'((:vlr-documenttobedeactivated
.
WJ:EPToBeDeactivated
)
)
) ;_ end of vlr-docmanager-reactor
) ;_ end of setq
() ;_ the reactor is already loaded
) ;_ end of if

(defun WJ:EPToBeActivated (In_ReactorName In_Command /)
(if (not blnFlag)
(progn
(setq blnFlag t)
(epcdchange)
)
)
) ;_ end of defun
(defun WJ:EPToBeDeactivated (In_ReactorName In_Command /)
(if blnFlag
(setq blnFlag nil)
)
) ;_ end of defun

the lisp for EPCDchange is already loaded in the drawing.

Opie
2009-08-21, 03:25 PM
Correct. Also, everytime AutoCAD loses focus, the deactivation reactor will fire and everytime it regains focus, the activation reactor will fire.

ccowgill
2009-08-21, 03:57 PM
tobeactivated may not be the best way to go. I dont think I want the regristry to be updated everytime I click on a different window and then come back to AutoCAD. Is there anyway to make it difinitive that it only occurs when a drawing is switched? Maybe the "Drawingbecamecurrent" event would be better than tobeactivated but I dont know what would replace tobedeactivated. Is there a way to combine the drawingbecamecurrent event and the drawingtobeactivated event, so that the callback function will only fire if both events occur?

Opie
2009-08-21, 05:44 PM
You can always check the registry before writing to it to make sure you are at the least making a change instead of overwriting the information with the same information. You could propogate a variable through all drawings with the value of the current registry key.

I think we can come up with something that will work.

The DocumentBecameCurrent does not mean the drawing was the currently active drawing. It means the drawing has been changed.

ccowgill
2009-08-21, 05:58 PM
You can always check the registry before writing to it to make sure you are at the least making a change instead of overwriting the information with the same information. You could propogate a variable through all drawings with the value of the current registry key.

I think we can come up with something that will work.

The DocumentBecameCurrent does not mean the drawing was the currently active drawing. It means the drawing has been changed.
Something like this:

(defun epcdchange ()
(if (/= (vl-registry-read
"HKEY_CURRENT_USER\\Software\\Eagle Point Software\\egpt\\EP\\"
"CurrentDrawing"
) ;_ end of vl-registry-read
(strcat (getvar "dwgprefix") (getvar "dwgname"))
) ;_ end of /=
(if
(and
(or
(wcmatch (strcase (vl-filename-base (getvar "dwgname")))
"RCP#####,RC######,RCPRF###,RCT#####,RCXSC###,SSHY####,STHY####"
) ;_ end of wcmatch
(vl-file-systime
(strcat (getvar "dwgprefix") (vl-filename-base (getvar "dwgname")) ".set")
) ;_ end of vl-file-systime
) ;_ end of or
(= (vl-registry-read
"HKEY_CURRENT_USER\\Software\\Eagle Point Software\\egpt\\EP\\"
"CurrentDataLocation"
) ;_ end of vl-registry-read
(getvar "dwgprefix")
) ;_ end of =
) ;_ end of and
(vl-registry-write
"HKEY_CURRENT_USER\\Software\\Eagle Point Software\\egpt\\EP\\"
"CurrentDrawing"
(strcat (getvar "dwgprefix") (getvar "dwgname"))
) ;_ end of vl-registry-write
(prompt "Not in Eagle Point")
) ;_ end of if
) ;_ end of if
(princ)
) ;_ end of defun

Opie
2009-08-21, 06:28 PM
That code looks like it would work.

Can I ask why you are looking at the project's .set file? What is the purpose of that?

ccowgill
2009-08-21, 06:51 PM
That code looks like it would work.

Can I ask why you are looking at the project's .set file? What is the purpose of that?
The .set file takes on the name that is specified for the initial base drawing, therefore I thought that if I determine what the name of the .set file is, I can determine if I am an an Eagle Point Base Drawing. but you do make a point, if there are multiple base drawings, set doesnt work, I really should be checking it to the .ddc file

Opie
2009-08-21, 07:23 PM
You can see a list of a few of the project files in the .epp and the .ifo files. Unfortunately, not all drawings are listed, such as RoadCalc generated files. There is also a registry key listing the CurrentGraphicKey as well as the CurrentRCSub. Using those, you might be able to determine if you are in one of the RC sub project drawings, which you are checking with your WCMatch function.

I don't have SS or ST modules, so I cannot test those.

ccowgill
2009-08-21, 07:29 PM
You can see a list of a few of the project files in the .epp and the .ifo files. Unfortunately, not all drawings are listed, such as RoadCalc generated files. There is also a registry key listing the CurrentGraphicKey as well as the CurrentRCSub. Using those, you might be able to determine if you are in one of the RC sub project drawings, which you are checking with your WCMatch function.

I don't have SS or ST modules, so I cannot test those.I know I am missing a few wcmatch names, but based on some of the projects we have, every base drawing that is part of a project gets a ddc file with the same name.

Opie
2009-08-21, 08:14 PM
In the project I am examining for this discussion, it contains the initial drawing for EP plus five more additional drawings. Out of those six drawings, only two have a corresponding .ddc file.

Of course if you have your data files located in a seperate folder from the base folder, the .ddc files will not be in the same folder as the drawing. There is a .ewg file in the same folder for each base / additional drawing as listed in the .epp file for the project.

ccowgill
2009-08-21, 08:27 PM
In the project I am examining for this discussion, it contains the initial drawing for EP plus five more additional drawings. Out of those six drawings, only two have a corresponding .ddc file.

Of course if you have your data files located in a seperate folder from the base folder, the .ddc files will not be in the same folder as the drawing. There is a .ewg file in the same folder for each base / additional drawing as listed in the .epp file for the project.
well then maybe ewg is a better file to compare. If you have your drawing in a separate folder, are the ewg files in the main project folder? Or are they stored in the directory with the actual dwg file?

ccowgill
2009-08-21, 08:47 PM
I am getting an infinite loop that keeps going whenever I have vlide opened and switch to AutoCAD, have you started experimenting with the actual program yet? are you experiencing an infinite loop with vlide open?

It may have something to do with my Vlide settings as to when it is activated and when AutoCAD is activated.

Opie
2009-08-21, 09:10 PM
The .ewg file is in the same folder as the associated drawing. However, there are no .ewg files for the drawings the modules create (RC######.dwg, SS######.dwg, etc.).

I did some minimal testing on 2007 last night with the reactors and associated routines. The activation routine popped an alert box. The deactivation only emptied the flag variable. After adding the flag check into the activation routine, the alert only showed once (maybe twice) per drawing activation.

After looking at your latest epcdchange routine, I do not see your flag check to specify you have already run the routine. That may be where you are getting your infinite loop. Or it might be because you are stepping through your routine, and everytime you change windows, the reactor fires.

ccowgill
2009-08-21, 09:16 PM
do I need to have the flag in the program, or can I use it in the reactor program?

(defun WJ:EPToBeActivated (In_ReactorName In_Command /)
(if (not blnFlag)
(progn
(setq blnFlag t)
(epcdchange)
)
)
) ;_ end of defun

I dont have any breakpoints in my code, so it isnt supposed to be stepping through.

Opie
2009-08-21, 09:26 PM
I had assumed they were the same program.

ccowgill
2009-08-21, 09:29 PM
I had assumed they were the same program.
sorry, no, I have my reactors broken up weird. I have an if statement to see if it is loaded, then I usually compare the event to a list, if the event matches, I run a particular program. So I kept this formatting for this program and I am calling the program (EPCDCHANGE) which is in a separate location from the reactor.
Here are my command started programs as an example:

(if (not Command_Starting_Reactor)
(setq Command_Starting_Reactor
(vlr-command-reactor
nil
'((:vlr-commandwillstart
.
Command_Started_Command
)
)
) ;_ end of vlr-command-reactor
) ;_ end of setq
() ;_ the reactor is already loaded
) ;_ end of if



(defun Command_Started_Command (In_ReactorName In_Command / LayObj)
(cond
((and (or
(= (car In_Command) "QLEADER")
(= (car In_Command) "MLEADER")
(= (car In_Command) "DIMALIGNED")
(= (car In_Command) "DIMLINEAR")
(= (car In_Command) "DIMCONTINUE")
(= (car In_Command) "DIMANGULAR")
) ;_ end of or
(or (= officelogan "WAIE") (= officelogan "WJI"))
) ;_ end of and
(c:dimstarted)
(c:q)
) ;_ end cond1
((and (or (= (car In_Command) "MVIEW")
(= (car In_Command) "-VPORTS")
(= (car In_Command) "VPORTS")
) ;_ end of or
(or (= officelogan "WAIE") (= officelogan "WJI"))
) ;_ end of and
(c:vpstarted)
) ;_ end cond2
) ;_ end of cond
) ;_ end of defun

ccowgill
2009-08-24, 01:56 PM
based on testing this weekend, everything seems to run fine, however, I am still getting an issue with AutoCAD locking up when I use VLIDE. So I'm going to add some coding to allow me to remove the reactor when I want to do coding, and some additional coding to reload the reactor when I'm done. It will all be manual, but as I and one other person are the only ones that will be doing any coding in our two offices, this shouldn't be an issue for the average end-user.

ccowgill
2009-08-28, 04:13 PM
Is there any sort of system variable that I can use to determine if VLIDE is open?