Hi, I’m exploring how the vtk server “event system” works.
I would like to ask a question about the “InvokeEvent” operation (server side).
Into the “protocols.py” there is the “mouseInteraction” method which has the following line:
self.getApplication().InvokeEvent('UpdateEvent')
Into the class “vtk_override_protocols.py” the event is intercepted by the method “addRenderObserver” which prepare the “callback” in the following way (click here to see the code on github):
observerCallback = lambda *args, **kwargs: self.pushRender(realViewId)
tag = self.getApplication().AddObserver('UpdateEvent', observerCallback)
So in that way each time the “UpdateEvent” is fired, the “pushRender” is invoked. That’s great!
My question is:
How can I send a value throught the “InvokeEvent” call?
Basically I need to pass a timestamp, so for example:
And I would like to read the value in the “pushRender” method.
Is that possible? Here I found some hints, but this is for the c++ staff, not for the python ones.
@dgobbi is there a user documentation of VTK’s Python wrapper? I couldn’t find a relevant section in in VTK API documentation and full-text search is not enabled, so I couldn’t even see if “vtk.calldata_type” is mentioned.
Thank you Andras,
at the end I figurated it out.
Thank you anyway for sharing me a couple of useful links and documentations.
Still have a couple of issues when passing the complex objects, but I will (hopefully) fix them in the next days.
Hi Andras,
just a quick question: I would like to pass a string or an vtk_object to the callback.
At the moment only a simple integer has been sent as value.
I tried to use VTK_STRING but the program unexpectedly exited (so I think an error has accured).
I really can’t figure out why is not working.
I just substituted the @vtk.calldata_type(vtk.VTK_LONG) with @vtk.calldata_type(vtk.VTK_STRING).
Is there something wrong here?
Sure, it’s the example in the doc string for calldata_type:
Help on function calldata_type in vtk:
vtk.calldata_type = calldata_type(type)
set_call_data_type(type) -- convenience decorator to easily set the CallDataType attribute
for python function used as observer callback.
For example:
import vtkmodules.util.calldata_type
import vtkmodules.util.vtkConstants
import vtkmodules.vtkCommonCore import vtkCommand, vtkLookupTable
@calldata_type(vtkConstants.VTK_STRING)
def onError(caller, event, calldata):
print("caller: %s - event: %s - msg: %s" % (caller.GetClassName(), event, calldata))
lt = vtkLookupTable()
lt.AddObserver(vtkCommand.ErrorEvent, onError)
lt.SetTableRange(2,1)
Or without bothering to import, you can use a string name for the type:
Thank you Eric and Andreas, ok I’ll give a second chance.
I wrote the same code you have in the example above, but maybe I misspelled it.
Thanks and regards
Ennio
Oops, I didn’t add anything to what you already knew. Do you know the C++ type of the object being passed, or is all your code pure Python? I’m guessing that mapping the object to VTK_LONG is simply casting and sending the address of whatever object is coming out of the C++ call, which is why it works. What’s the value of that parameter on the receiving end when you use VTK_LONG?
More importantly, does InvokeEvent have a second parameter? I can’t find its definition to verify, but all the examples I’ve scanned simply allow a single, event name parameter.
Ok finally it worked.
I figured out what was the problem: I was passing a python object which was “”“containing”“” a string.
In other words: I didn’t “typitize” it as a string.
So in my final solution I used:
self.getApplication().InvokeEvent('UpdateEvent', str(stringArgument)) # WORKING SOLUTION
So finally it’s working with @vtk.calldata_type(vtk.VTK_STRING)
Thank you so much!
Ennio
PS:
What’s the value of that parameter on the receiving end when you use VTK_LONG ?
I printed it out and it is: ‘8’
“VTK_STRING” is: ‘13’
And I’m happy to say that it’s working with the following as well:
@vtk.calldata_type('string0') # THIS ONE WORKS AS WELL :-)
Thanks!!
PPS:
last question: I was wondering if there is a way to pass an Object (maybe it could be usefull in the future). In the meanwhile I can use a string array as “Andreas” suggested.
Hi Andras, I’ve been on vacation and haven’t been able to read through this thread yet, @jcfr implemented parts of the python event code and he might be able to answer.
If you want to pass custom Python objects, then you can serialize it to string: create a json representation manually; or use pickle to get a byte array and convert to string using base-64 encoding.
Thank you to everyone.
I think I’m definitely ready to master the callbacks arguments
Really appreciate the time and patience you put in this thread
Ennio
Ennio, in the VTK C++ source, the second parameter (callData) is a void*. From the VTK Python Wrappers docs:
a void* pointer can accept a pointer in two different ways: either from an Python object that supports the Python buffer protocol (this includes all numpy arrays along with the Python bytes and bytearray types), or from a string that contains a mangled pointer for the form '_hhhhhhhhhhhh_p_void', where 'hhhhhhhhhhhh' is the hexadecimal address. Return-valid void* will always be a string containing the mangled pointer.
This is why wrapping it in a str() worked: you called the object’s __str__() that returned its string representation.