Author Topic: AcDbReactor, ObjectModified - Just looking for quick opinions... will it work?  (Read 850 times)

0 Members and 1 Guest are viewing this topic.

Rustabout

  • Newt
  • Posts: 135
DON'T run this code before reading this. Better yet don't run the code at all ;-) .

I'm made a database reactor and I've broken one of the rules: Modifying the object that called the reactor. I've noticed that even if I use the database reactor and modify a line, the reactor is called like 20 times. For more complex geometry (like the dynamic block in this case), it can be called upwards of 30 times just for one small modification.
I could create an object reactor... but... that's a lot of work, and I run into the same issue: that is modifying the object that triggered the reactor, unless I make the tag a separate object.... which......... I've done in a past life. Let's just say I would probably bail and use a different means to achieve the end goal here.

So... have a quick look at this code (DON'T run it... unless you're extremely adventurous or want to tweak/play around). Will it work and there's just something I'm missing? Or per above is it doomed to fail? It will work but then sporadically I start getting all sorts of crazy error messages; it literally starts to behave similar to unsafe code, but I think (I think!!) ACAD will crash before any real damage is done. I'm only encouraging quick feedback as I might try a different approach altogether. I'd hate for someone to spend a massive amount of time on this unless it helps them out in some way as well.

I've attached a file to help demo what I'm doing.

Code - Auto/Visual Lisp: [Select]
  1.   (vlr-AcDb-Reactor "kCs-ObjectModifiedReactor" '((:VLR-ObjectModified . OnObjectModified)))
  2.   (progn
  3.     (vlr-AcDb-Reactor "kCs-ObjectModifiedReactor" '((:VLR-ObjectModified . OnObjectModified)))
  4.    )
  5.   ) ; end if
  6.  
  7. (defun OnObjectModified ( _callingReactor _objectInfo / object)
  8.  
  9.   (setq object (vlax-ename->vla-object (car (cdr _objectInfo))))
  10.  
  11.   (if (= (type object) 'VLA-OBJECT)
  12.     (if (vlax-property-available-p object 'objectName)
  13.       (if (= (vla-get-objectName object) "AcDbBlockReference")
  14.         (if (vlax-property-available-p object 'EffectiveName)
  15.           (if (= (vla-get-effectiveName object) "#-TEST BLOCK")
  16.             (UpdatePadFootingDescription object)
  17.             )
  18.           )
  19.         )
  20.       )
  21.     )
  22.        
  23.    
  24.  
  25.  ) ; end defun
  26.  
  27. ; ---------------------------------------------------------------------------------------
  28.  
  29.  
  30. (defun UpdatePadFootingDescription ( _obj / )
  31.  
  32.   (EditAttributeValue "TEST_TAG" (CreatePadFootingTextString _obj) _obj)
  33.  
  34.  ) ; end defun __________________________________________________________
  35.  
  36. ; -----------------------------------------------------------------------
  37.  
  38. (defun EditAttributeValue ( _attTag _text _obj / )
  39.  
  40.   (setq tag (strcase _attTag))
  41.     (vl-some
  42.        '(lambda (att)
  43.             (if (= tag (strcase (vla-get-tagstring att)))
  44.                (vla-put-textstring att _text)
  45.             )
  46.         )
  47.         (vlax-invoke _obj 'getattributes)
  48.       )
  49.   ) ; end defun __________________________________________
  50.  
  51. ; --------------------------------------------------------------------
  52.  
  53. (defun GetDynamicBlockPropertyValue (_propName _obj / propValue )
  54.  
  55.   (setq propValue -1) ; *** if this is not changed, it means there is an error.
  56.  
  57.     '(lambda (prop)
  58.        (if (= (strcase _propName) (strcase (vla-get-propertyName prop)))
  59.          (setq propValue (vlax-variant-value (vla-get-value prop)))
  60.         )
  61.        )
  62.     (vlax-invoke _obj 'getDynamicBlockProperties)
  63.    )
  64.  
  65.    (eval propValue)
  66.  
  67.   ) ; end defun _____________________________________________________________
  68.  
  69. (defun CreatePadFootingTextString ( _obj / lengthString widthString depthString textString)
  70.  
  71.   (setq lengthString (ConvertInchesToFeetToString (GetDynamicBlockPropertyValue "Length" _obj)))
  72.   (setq widthString (ConvertInchesToFeetToString (GetDynamicBlockPropertyValue "Width" _obj)))
  73.   (setq depthString (ConvertInchesToFeetToString (GetDynamicBlockPropertyValue "Depth" _obj)))
  74.  
  75.   (setq textString (strcat lengthString "' x " widthString "' x " depthString "' dp. Pad Footing"))
  76.  
  77.   (eval textString)
  78.  
  79.  ) ; end defun _________________________________________________________________________________
  80.  
  81. (defun ConvertInchesToFeetToString ( _input / )
  82.  
  83.   (eval (rtos (/ _input 12.0) 2 2))
  84.  
  85.  ) ; end defun _________________________________
  86.  
  87.  

« Last Edit: December 20, 2022, 07:40:11 PM by Rustabout »

Rustabout

  • Newt
  • Posts: 135
Two things I'm going to try before giving up (unless I get some other ideas :-D):

Seeing if I can switch the reactor off in the callback function prior to modifying the object, and then back on after the object is modified.

And using a different reactor: In this particular case for example, running the reactor when the objected is unselected would achieve the same result.

mhupp

  • Bull Frog
  • Posts: 250
DON'T RUN CODE

Maybe have it in bold red?

Rustabout

  • Newt
  • Posts: 135
Suggestion acknowledged and implemented.

This is an old style of forum but it's pretty damn good... only takes a minute or two to figure out how to make nice looking posts.

Rustabout

  • Newt
  • Posts: 135
I've updated the code with one of my suggestions: That being removing the reactor prior to modifying any objects, and then re-instating the reactor (forgive my terminology) after any changes are applied. This is easy to manage so long as I'm aware of what reactors I'm running (and not using anyone else's stuff for example). Even if I have multiple database reactors I would just incorporate a sub function.

I'm just adding (vlr-remove-all :vlr-AcDb-Reactor) before and...

(if (= nil (vlr-reactors :vlr-AcDb-Reactor))
    (vlr-AcDb-Reactor "kCs-ObjectModifiedReactor" '((:VLR-ObjectModified . OnObjectModified)))
    (progn
      (vlr-remove-all :vlr-AcDb-Reactor)
      (vlr-AcDb-Reactor "kCs-ObjectModifiedReactor" '((:VLR-ObjectModified . OnObjectModified)))
     )
    )

after

SO FAR it doesn't crash, even with this many blocks and editing them all at the same time. But we'll see.


Rustabout

  • Newt
  • Posts: 135
Update: It seems that autosaving is busting the reactor while creating an access violation error (well... disabling it at least). But at least it's not crashing like it was before. Either way I might have to abandon this. I love what reactors can do but they're just so unpredictable (sometimes).

For anyone who's curious: You can achieve something similar (better actually) using object reactors. But it requires a very organized and well thought-out approach, and will produce a wack of error messages if the callback function isn't loaded after the file is closed and reopened (if I recall... it's been awhile).

Rustabout

  • Newt
  • Posts: 135
I've since gone the .NET direction with far better results so far. Had to learn a few new things of course. And I've gone the route of using object events instead of database events. I haven't decided how to apply my event handler to the objects yet but I think there's more than a few approaches I can use for that.

Only posting an update because I think that the database reactor was the wrong way to go for something like this.