Saturday Snippet

This is a bit of a snippet and a bit of a flashback. Back in the early days of “Sumatra scripting” (14 years ago), commands like GetValue didn’t have a return value. They had output arguments and you had to go through the ISIVTCollection to get the output value.

Here’s a classic example of the .Value(“Value”) syntax.

Name = GetValue("Sphere.Name").Value("Value")

ISIVTCollections, output arguments, and implicit return values

Commands that don’t explicitly define a return value, but do have output arguments, have an implicit return value: an ISIVTCollection.

The ISIVTCollection is a “special type of collection”, but it may help to think of it as [something like] a dictionary. An ISVTCollection holds a collection of key, value pairs (like a Python dictionary). You use the key names, like “Value”, to extract the associated value.

For example, the PickElement command has three “output arguments”; that is, parameters that return some value. These output arguments are PickedElement, ButtonPressed, and ModifierPressed.

So PickElement returns an ISIVTCollection collection with three key-value pairs. The keys are “PickedElement”, “ButtonPressed”, and “ModifierPressed”.

You can use the ISIVTCollection.Value method to get the value of a key:

from sipyutils import si			# win32com.client.Dispatch('XSI.Application')
from sipyutils import log		# LogMessage
from sipyutils import C			# win32com.client.constants
si = si()

vtcol = si.PickElement(C.siObjectFilter, "Pick deformer")

button = vtcol.Value( "ButtonPressed" )
modkey = vtcol.Value( "ModifierPressed" )
o = vtcol.Value( "PickedElement" )

There’s also an Item property, but like most Item properties it fails in Python:

vtcol = si.PickElement(C.siObjectFilter, "Pick deformer")
o = vtcol.Item( "PickedElement" )
# ERROR : Traceback (most recent call last):
#   File "<Script Block >", line 7, in <module>
#     o = vtcol.Item( "PickedElement" )
# TypeError: 'NoneType' object is not callable

Fortunately, Item is the default property, so you can omit it:

vtcol = si.PickElement(C.siObjectFilter, "Pick deformer")
o = vtcol( "PickedElement" )

You can also use an integer index instead of the key string. It just so happens that ISIVTCollections are sorted by key name (case insensitive), so you can work out which index to use.

# ISIVTCollection is sorted by name (case insensitive)
# 0 = ButtonPressed
# 1 = ModifierPressed
# 2 = PickedElement
o = si.PickElement(C.siObjectFilter, "Pick deformer")(2)

print ( si.ClassName(o) )
# X3DObject