Author Topic: Run a lisp routine when a field is selected for editing.  (Read 3165 times)

0 Members and 1 Guest are viewing this topic.

Cawaugh

  • Guest
Run a lisp routine when a field is selected for editing.
« on: January 08, 2013, 04:41:35 PM »
I have a situation where I would like to run a lisp routine whenever someone tries to edit a field in a particular attribute.
I do not want the field to be manually updated but only updated when the user runs the program.
Any thoughts?
« Last Edit: January 08, 2013, 04:57:38 PM by Cawaugh »

BlackBox

  • King Gator
  • Posts: 3770
Re: Run a lisp routine when a field is selected for editing.
« Reply #1 on: January 08, 2013, 05:48:16 PM »
... Perhaps an Object Reactor:?
"How we think determines what we do, and what we do determines what we get."

Cawaugh

  • Guest
Re: Run a lisp routine when a field is selected for editing.
« Reply #2 on: January 09, 2013, 07:45:58 AM »
I don't know much about reactors. in doing some research on them I can see how this could work. This is what I was trying to no avail: (vlr-object-reactor e1 "Run Code Eval" '((:vlr-modified . code_eval1))). e1 was set by doing an ssget on my title block but I do not believe this is the correct "Owner" to go here. I'm trying to run the code_eval1 program every time someone finishes editing the title block.

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: Run a lisp routine when a field is selected for editing.
« Reply #3 on: January 09, 2013, 09:01:23 AM »
Perhaps one of these will help.
http://goo.gl/0NswR

No time this morning to look further.
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

dgorsman

  • Water Moccasin
  • Posts: 2437
Re: Run a lisp routine when a field is selected for editing.
« Reply #4 on: January 09, 2013, 11:08:43 AM »
I don't know much about reactors. in doing some research on them I can see how this could work. This is what I was trying to no avail: (vlr-object-reactor e1 "Run Code Eval" '((:vlr-modified . code_eval1))). e1 was set by doing an ssget on my title block but I do not believe this is the correct "Owner" to go here. I'm trying to run the code_eval1 program every time someone finishes editing the title block.

Object reactors can be a little tricky.  For one, you can't use the code called by the reactor to modify the object which fired the reactor (insert "Who's on First?" sketch here!   ;-)  ).  The second problem is the reactor must be loaded when the drawing is opened, which can present certain logistical problems.  Fallout from that, is that you can't do anything about a drawing that leaves your control, either.

What the object reactor would have to do is log the object ID which called the reactor (typically as an entity reference or handle), enable a second reactor to handle the command-ended event which would process the logged items to restore the field(s) then disable the second reactor (PITA - I've investigated this).  In terms of work involved, you *might* be better off putting those attributes on a locked layer and requiring users to use your own code to modify the attribute information.
If you are going to fly by the seat of your pants, expect friction burns.

try {GreatPower;}
   catch (notResponsible)
      {NextTime(PlanAhead);}
   finally
      {MasterBasics;}

BlackBox

  • King Gator
  • Posts: 3770
Re: Run a lisp routine when a field is selected for editing.
« Reply #5 on: January 09, 2013, 11:33:04 AM »
Thanks for jumping in Dgorsman... I'm short on time, but wanted to clarify further... nice job, Sir.

The only think I can think to add (quickly), is that further adding to the complexity, the OP must avoid Command calls as well (within the Callback function(s)).  :-)
"How we think determines what we do, and what we do determines what we get."

Cawaugh

  • Guest
Re: Run a lisp routine when a field is selected for editing.
« Reply #6 on: January 09, 2013, 03:13:20 PM »
The comments have gone over my head. I have not worked with reactors but the idea was given to me to check them out for what I need to do. Unfortunately, several sample codes I found and tried worked up until I wanted to run a lisp routine. The lisp routine works just fine on it's own but the total package (reactor code plus the eval code) crashes. All I wanted to do was run the eval code any time the title block was edited manually. I'll keep looking, thanks for the help. If anyone comes up with something, i'm listening! ^-^

BlackBox

  • King Gator
  • Posts: 3770
Re: Run a lisp routine when a field is selected for editing.
« Reply #7 on: January 09, 2013, 03:47:21 PM »
Perhaps you could post the 'eval code' so that we might better suggest a solution?
"How we think determines what we do, and what we do determines what we get."

Cawaugh

  • Guest
Re: Run a lisp routine when a field is selected for editing.
« Reply #8 on: January 09, 2013, 04:43:36 PM »
I'm heading out but will post it tomorrow. Thanks!

Cawaugh

  • Guest
Re: Run a lisp routine when a field is selected for editing.
« Reply #9 on: January 10, 2013, 01:39:10 PM »
The callback code_eval2 works just fine when I tested it against a command reactor on a save, tsee below code:
(vl-load-com)
(if (not *caw-CommandReactors*)
  (setq  *caw-CommandReactors*
            (vlr-command-reactor nil '((:vlr-commandWillStart . StrtCMD)))
  );end setq
);end if
(defun StrtCMD (calling-reactor StrtCMDInfo / theCMDStrt)
  (setq theCMDStrt (strcase (nth 0 StrtCMDInfo) t))
  (cond
    ((wcmatch theCMDStrt "*save*")
     (code_eval2)
    );end wcmatch
  );end cond
);end defun


When I try and use an object reactor, testing for a change in the title block with the below code, nothing happens.
What am I missing? The best scenerio would be to test to see if a particular attribute was change then run the eval instead of just a random change to the title block.

(vl-load-com)
(setq ss (ssget "X" '((-4 . "<AND") (0 . "INSERT") (2 . "3M-BORDER*")
          (-4 . "<NOT") (2 . "3M-BORDER-DIVISION") (-4 . "NOT>")
          (-4 . "<NOT") (2 . "3M-BORDER-FACILITIES") (-4 . "NOT>")
          (-4 . "<NOT") (2 . "3M-BORDER-LABORATORY") (-4 . "NOT>")
          (-4 . "<NOT") (2 . "3M-BORDER-PICS") (-4 . "NOT>")
          (-4 . "<NOT") (2 . "3M-BORDER-SME") (-4 . "NOT>")
          (-4 . "AND>")))
);end setq ss
(if ss
(setq  vlr-object
  (vlr-object-reactor
  (list (vlax-ename->vla-object (ssname ss 0.0))) "Title Block Updated!" '((:vlr-modified . TBmod)))
);end setq
);end if
(defun TBmod (notifier reactor parameter)
  (vl-load-com)
  (code_eval2)
);end defun



Thanks!

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: Run a lisp routine when a field is selected for editing.
« Reply #10 on: January 10, 2013, 01:54:42 PM »
Remember that an object with an object reactor can not modify itself within the reactor.
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

Cawaugh

  • Guest
Re: Run a lisp routine when a field is selected for editing.
« Reply #11 on: January 10, 2013, 02:00:25 PM »
I'm not modifing the title block. I want to run a eval (which doesn't modify the tb) after the title block has been modified.
Does that make sense how i want to do it?

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Run a lisp routine when a field is selected for editing.
« Reply #12 on: January 10, 2013, 11:21:00 PM »
Here is something to get you started.  Not fool-proof or anything, but works with the basic idea.

Code: [Select]
(defun c:TestReact ( / Ent Obj )
   
    (defun reactObjChange ( obj react notSure )
       
        (if (not (wcmatch (getvar "CmdNames") "U,UNDO,REDO,OOPS"))
            (progn
                (setq GlbVarAttributeChanged (cons obj GlbVarAttributeChanged))
                (if (not GlbReactorAttributeCommandEnd)
                    (setq GlbReactorAttributeCommandEnd
                        (vlr-command-reactor
                            "tempAttributeCommandReactor"
                            '((:vlr-commandEnded . reactAttributeChange))
                        )
                    )
                )
            )
        )
        (princ)
    )
    ;-------------------------------------------------------
    (defun reactAttributeChange ( react cmdList )
       
        (if (not (member "CMDNAME" (mapcar (function strcase) cmdList)))
            (foreach i GlbVarAttributeChanged
                (if (setq tempList (assoc i GlbVarAttributeValueList))
                    (vla-put-TextString (car tempList) (cdr tempList))
                )
            )
        )
        (setq GlbVarAttributeChanged nil)
        (vlr-remove GlbReactorAttributeCommandEnd)
        (setq GlbReactorAttributeCommandEnd nil)
        (princ)
    )
    ;-----------------------------------------------------------
    (defun reactObjErased ( obj react notSure )
   
        (vlr-pers-release react)
        (vlr-remove react)
    )
    ;--------------------------------------------------------------
   
    (if
        (and
            (setq Ent (nentsel "\n Select attribute: "))
            (= (cdr (assoc 0 (entget (car Ent)))) "ATTRIB")
            (setq Obj (vlax-ename->vla-object (car Ent)))
        )
        (progn
            (foreach i (cdar (vlr-reactors :vlr-object-reactor))
                (if
                    (and
                        (vl-position Obj (vlr-owners i))
                        (= (vlr-data i) "AttributeReactorChanged")
                    )
                    (progn
                        (vlr-pers-release i)
                        (vlr-remove i)
                    )
                )
            )
            (vlr-pers
                (vlr-object-reactor
                    (list Obj)
                    "AttributeReactorChanged"
                    '(
                        (:vlr-modified . reactObjChange)
                        (:vlr-erased . reactObjErased)
                    )
                )
            )
            (if GlbVarAttributeValueList
                (if (setq tempList (assoc Obj GlbVarAttributeValueList))
                    (setq GlbVarAttributeValueList (subst (cons Obj (vla-get-TextString Obj)) tempList GlbVarAttributeValueList))
                    (setq GlbVarAttributeValueList (cons (cons Obj (vla-get-TextString Obj)) GlbVarAttributeValueList))
                )
                (setq GlbVarAttributeValueList (list (cons Obj (vla-get-TextString Obj))))
            )
        )
    )
    (princ)
)
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Run a lisp routine when a field is selected for editing.
« Reply #13 on: January 11, 2013, 12:00:50 AM »
If you want to know "why" this happens: An object reactor fires when the object is changed. The change has already placed a lock on the object, thus until the command which changed the object completes nothing else may change the object. So nothing in the reactor is allowed to change its object.

That's why dgorsman suggested the 2 tiered reactor approach: I.e. the object reactor simply saves the object(s) into a global list. A second command-ended reactor checks this list and then performs the eval on each object in that. That way the eval happens after the original changing command has finished.

BTW, I'm not sure if such would work if the user changes the attribute value through the Properties Palette. I mean: seeing as there's not actually a command which runs. So it's quite possible that the eval will only execute after the user issues another command.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

Cawaugh

  • Guest
Re: Run a lisp routine when a field is selected for editing.
« Reply #14 on: January 11, 2013, 09:06:39 AM »
Good morning, Tim. It's been a while. i'm heading into a meeting but when i get back could i give you a call? here is my email so you can send me your telephone number (if thats ok). charles.waugh@wmeng.com.

Thanks!