Reactors and the UNDO command

Discussion in 'AutoCAD' started by archie999, Mar 30, 2005.

  1. archie999

    archie999 Guest

    Hi,

    I have written a program which sets reactors to certain objects which causes run a LISP program when they are modified - This bit works fine.

    I have now added a bit to remove the reactor when the object is deleted by the user so that an error doesn't occur.

    But I've noticed that if the user accidently deletes the object which has the modify reactor set on it, and then types UNDO to restore it - it comes back but the reactor is not restored.

    AutoCAD users expect the UNDO command to restore everything back to its original state - this seems not to be the case with an object that has a reactor on it - The user wont realise that the restored objects will now not run the LISP program when modified?

    (BTW I am using UNDO GROUP and UNDO END in the lisp program)

    Is this the case - Or am I missing something??
     
    archie999, Mar 30, 2005
    #1
  2. It helps to see what you are doing.... or post the part of your code, you
    think is causing the problems.

    Anyway, here is little sample about Visual Lisp object reactors, to always
    change a block with two attributes the value of the fist attribute with the
    second one.

    In this case, notice if you delete/erase any of the blocks and when undo is
    issue, the reactor are kept or restore.

    Make a block made with two attributes, and then test the routine....

    ;; code
    (vl-load-com)

    (defun commandended
    (reactor params / atts att1 att2 text_att1 text_att2)
    (if modified_list
    (foreach blk modified_list
    (setq atts
    (reverse (vlax-safearray->list
    (vlax-variant-value (vla-getattributes blk))))
    att1 (car atts)
    att2 (cadr atts)
    text_att1 (vla-get-textstring att1)
    text_att2 (vla-get-textstring att2))
    (if (/= text_att2 text_att1)
    (vla-put-textstring att1 (vla-get-textstring att2)))))
    (setq modified_list nil))

    (defun subobjmodified (owner reactor params)
    (if (and (not (wcmatch (getvar "cmdnames") "UNDO,U,REDO,OOPS"))
    (not (vl-position owner modified_list)))
    (setq modified_list (cons owner modified_list))))

    (defun C:TEST (/ obj obj_reactor)
    (setq obj (vlax-ename->vla-object
    (car (entsel "\nSelect block with two attributes: "))))

    (if (not editor_reactor)
    (setq editor_reactor
    (vlr-editor-reactor
    "editor"
    '(:)vlr-commandended . commandended)))))

    (setq obj_reactor
    (vlr-object-reactor
    (list obj)
    "obj"
    '(:)vlr-subobjmodified . subobjmodified))))
    (princ))

    (princ)
    ;; code

    HTH

    LE.

    causes run a LISP program when they are modified - This bit works fine.
    the user so that an error doesn't occur.
    the modify reactor set on it, and then types UNDO to restore it - it comes
    back but the reactor is not restored.
    original state - this seems not to be the case with an object that has a
    reactor on it - The user wont realise that the restored objects will now not
    run the LISP program when modified?
     
    Luis Esquivel, Mar 30, 2005
    #2
  3. AutoCAD users expect the UNDO command to restore
    The user shouldn't have to think about what happens when
    an object is modified. Users shouldn't be required to be
    that familiar with the details of customization.

    Why are you removing the reactor when the object is
    erased? What error occurs if you don't remove the
    reactor?
     
    Tony Tanzillo, Mar 30, 2005
    #3
  4. archie999

    archie999 Guest

    Tony / Luis,

    The program is basically for adding the area of a polyline into a block attribute - so when the polyline is modified in amy way the area is then updated in the block attribute.

    I have a reactor set on the polyline which run a LISP which measures the polylines area then updates the block attribute.

    I also have a reactor on the block which warns the users when he deletes it - it tells the users that the block which was just deleted belonged to a polyline - (Just out of interest - if the user does delete the block and then type UNDO the reactor all is restored including the reactors).

    The above works fine - the following conditions occur which I was trying to stop by removing the reactor;

    - The block is delete - When the users now modifies the polyline the LISP program then fails and generates an error as the block doesn't exist.

    - The polyline is deleted - Not much of a problem but for good housekeeping I would now like to remove the reactor on the block.

    Also, if the reactor has owners which have been deleted it generates a non critical error the next time the drawing is loaded

    This is the routine I use for removing the reactors which will be called when either the block or polyline is deleted. (this is the LISP which the UNDO command does seem to restore the reactors)

    (defun check (qobject / ObjRea
    foundreactor ReaLst reaitem
    objrea-ename reaitem-ename objrea-handle
    reaitem-handle
    )

    (setq ObjRea (vlax-ename->vla-object qobject)
    foundreactor nil
    ReaLst (mapcar
    '(lambda (l)

    (cons (car (vlr-owners l)) l)
    )
    (cdar (vlr-reactors :vlr-object-reactor))
    )
    )

    (foreach reaitem realst

    (setq objrea-ename (vlax-vla-object->ename objrea)
    reaitem-ename (vlax-vla-object->ename (car reaitem))
    objrea-handle (cdr (assoc 5 (entget objrea-ename)))
    reaitem-handle (cdr (assoc 5 (entget reaitem-ename)))
    )

    (if (= reaitem-handle objrea-handle)
    (setq foundreactor reaitem)
    )

    )

    (princ foundreactor)

    )



    (defun c:removereactorboth (/ mainob otherob)

    (command "undo" "group")

    (setq mainob (check (car (entsel)))
    otherob (check (handent (vlr-data (cdr mainob))))
    )

    (vlr-owner-remove (cdr mainob) (car mainob))
    (vlr-owner-remove (cdr otherob) (car otherob))

    (command "undo" "end")
    (princ)

    )

    The programs a bit rough and ready and I have just put it together ...

    Luis - I haven't had a chance to look at your routine - I'll do that now...
     
    archie999, Mar 31, 2005
    #4
  5. archie999

    archie999 Guest

    Luis,

    I seem to be able to recreate the problem with your LISP.

    If you load my program then type;

    (setq mainob (check (car (entsel))))

    And then select the block, then type:

    (vlr-owner-remove (cdr mainob) (car mainob))

    The reactor is removed - but UNDO doesn't bring the reactor back...
     
    archie999, Mar 31, 2005
    #5
  6. archie999

    archie999 Guest

    Oops - I should have written - load your routine first and set up a block and run your test routine on it and then load my routine and type:

    (setq mainob (check (car (entsel))))
    (vlr-owner-remove (cdr mainob) (car mainob))
     
    archie999, Mar 31, 2005
    #6
  7. Is Archie your real name?


    I added the erased event on my object reactor and remove the reactor and
    also I have a function to remove vlr-owners and vlr-data and I have no
    problems with the undo.


    LE
     
    Luis Esquivel, Mar 31, 2005
    #7
  8. archie999

    archie999 Guest

    Luis,

    How did you get it to work? Did you use my routine?

    "I have a function to remove vlr-owners and vlr-data "

    Do you think its a problem with my code?
     
    archie999, Apr 1, 2005
    #8
  9. Yes.

    In order to recreate the reactor, you must do the following:

    1. Have the ERASED event in your reactor
    2. Inside the ERASED function callback, do the appropriate for the DATA part.
    Code:
    (defun erased  (owner reactor params)
    (vlr-owner-remove reactor owner)
    (vlr-data-set reactor nil)
    (vlr-remove reactor))
    
    If I use your function, I am destroying the reactor before using erase, that is the reason the reactor is not being recreated.

    Have fun,
    Luis.
     
    Luis Esquivel, Apr 1, 2005
    #9
  10. archie999

    archie999 Guest

    Hi Luis,

    I still dont understand why I need to do as you suggets.

    Although eventually I want to get the routine to deal with the user erasing the object with the reactor on it, the routine I posted just deals with removing a reactor - (I will do the erase bit later).

    Check out this lisp in which I have put together the following functions;

    c:test - This is your function which sets up a reactor which copies attributes

    check - This is my fuction which returns the name of a reactor set on an object

    erased - this from your previous post which removes the data and reactor from an object

    c:killreactor - this is the main fuction which lets the user select an object then it run check and erased.



    (defun commandended
    (reactor params / atts att1 att2 text_att1 text_att2)
    (if modified_list
    (foreach blk modified_list
    (setq atts
    (reverse (vlax-safearray->list
    (vlax-variant-value (vla-getattributes blk))
    )
    )
    att1 (car atts)
    att2 (cadr atts)
    text_att1 (vla-get-textstring att1)
    text_att2 (vla-get-textstring att2)
    )
    (if (/= text_att2 text_att1)
    (vla-put-textstring att1 (vla-get-textstring att2))
    )
    )
    )
    (setq modified_list nil)
    )

    (defun subobjmodified (owner reactor params)
    (if (and (not (wcmatch (getvar "cmdnames") "UNDO,U,REDO,OOPS"))
    (not (vl-position owner modified_list))
    )
    (setq modified_list (cons owner modified_list))
    )
    )




    (defun C:TEST (/ obj obj_reactor)
    (setq obj (vlax-ename->vla-object
    (car (entsel "\nSelect block with two attributes: "))
    )
    )

    (if (not editor_reactor)
    (setq editor_reactor
    (vlr-editor-reactor
    "editor"
    '(:)vlr-commandended . commandended))
    )
    )
    )

    (setq obj_reactor
    (vlr-object-reactor
    (list obj)
    "obj"
    '(:)vlr-subobjmodified . subobjmodified))
    )
    )
    (princ)
    )

    (princ)





    (defun check (qobject /)

    (setq ObjRea (vlax-ename->vla-object qobject)
    foundreactor nil
    ReaLst (mapcar
    '(lambda (l)

    (cons (car (vlr-owners l)) l)
    )
    (cdar (vlr-reactors :vlr-object-reactor))
    )
    )

    (foreach reaitem realst


    (setq objrea-ename (vlax-vla-object->ename objrea)
    reaitem-ename (vlax-vla-object->ename (car reaitem))

    )

    (if (/= objrea-ename nil)
    (setq objrea-handle (cdr (assoc 5 (entget objrea-ename))))
    (setq objrea-handle nil)
    )
    (if (/= reaitem-ename nil)
    (setq reaitem-handle (cdr (assoc 5 (entget reaitem-ename))))
    (setq reaitem-ename nil)
    )




    (if (= reaitem-handle objrea-handle)
    (setq foundreactor reaitem)
    )

    )
    (princ foundreactor)

    )




    (defun erased (owner reactor params)
    (princ "\nOK1")
    (vlr-owner-remove reactor owner)
    (princ "\nOK2")
    (vlr-data-set reactor nil)
    (princ "\nOK3")
    (vlr-remove reactor)
    (princ "\nOK4")
    )



    (defun c:killreactor ()

    (setq getobject (car (entsel))) ; User picks object

    (setq objectsreactor (check getobject))
    ; Finds the reactor on the object

    (princ "\nOK to here")

    (erased (car objectsreactor) (cdr objectsreactor) nil)
    ; Removes the reactor
    )


    If you now make a block with two attributes, then run test on it and then type "Killreactor" and select the block - it removes the reactor from the object.

    But if I type UNDO - It doesn't come back (I'm not trying to erase anything at this point) - I'm just trying to get the UNDO command to restore the reactor just as it restores anything else which the user does.

    Thanks for your help on this Luis - Any advise??
     
    archie999, Apr 4, 2005
    #10
  11. I still dont understand why I need to do as you suggets.

    All will depend on you... I am just posting what I know.
    erasing the object with the reactor on it, the routine I posted just deals
    with removing a reactor - (I will do the erase bit later).

    You can not use UNDO if you kill the reactor, the only way you can get it
    back is by having the erased event in your reactor.

    You may try to have a list of those objects [inside of the check function]
    and in the commandended event check for the UNDO,U command and re-create the
    reactor over there.

    LE.
     
    Luis Esquivel, Apr 4, 2005
    #11
Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.