okay here "simple" examples about why I have to define callbacks as
strings instead of code.

In XSI, one of the GUI objects that you can create is called a "custom
property". A custom property is basically a floating window in which
there are widgets. Custom properties can define a layout or not.

Custom properties that do not define a layout display a bunch of
simple widgets (text fields, sliders for scalar values, checkboxes,
etc), vertically on top of each other.

Custom properties that define a layout offer a lot more interesting
widgets: buttons, tabs, combo boxes, radio buttons, labels, groups,
etc. To interactive widgets, callbacks can be attached. So when a
button is clicked or a combo box changed, code can be ran.


There are two implementations for custom property layouts.

1- property plugins: the entire property is defined in a plugin file.
Here the programmer can put any amount of widgets and callbacks he
wants. However, the number of such items is constant, one cannot
dynamically add or remove elements from a property created in that
fashion. (well, perhaps it is possible, but I don't know how).

When the XSI application starts, the plugin is loaded. In scripts, the
property can be instantiated and inspected.

The great benefit of this approach is that the property's layout and
logic are persistable. Since those are defined in a plugin, if the
plugin is always found, then the property will keep its layout and
logic, even if the document is closed and reopen.

Here is an example of such a plugin:


# Load plugin in XSI

def XSILoadPlugin( in_reg ):
        in_reg.Author = "Bernard Lebel"
        in_reg.Name = "plugindemo"
        in_reg.Major = 1
        in_reg.Minor = 1
        in_reg.RegisterProperty( "propertyplugindemo" )
        return True

# Define property

def propertyplugindemo_Define( io_Context ):
        """ Add parameters """
        oProp = io_Context.source
        oProp.addparameter3( 'myparameter', 8, '' )

def propertyplugindemo_DefineLayout( io_Context ):
        """ Skip layout creation. We'll do it at inspection time. """
        pass    
        
def propertyplugindemo_OnInit():
        """ Called when the property is inspected
        (brought up to the screen for the user to use it) """
        oProp = PPG.Inspected(0)
        
        # Create property layout
        oLayout = PPG.PPGLayout
        oLayout.Clear()
        
        oLayout.additem( 'myparameter', 'myparameter' ) # add "myparameter text 
field"
        oLayout.addbutton( 'myButton' ) # add "myButton" button
        
        PPG.Refresh()

# Callbacks for widgets
def propertyplugindemo_myButton_OnClicked():
        print 'hello world'


2- on-the-fly logic: instead of creating a plugin, the programmer can
create a custom property along with layout and logic entirely at
execution time. While this prevents the property layout and logic from
being persisted, it allows the programmer to define dynamically how
many widgets and callback he wants.

The problem with this approach is that it I believe it was not
designed with Python in mind, but rather JScript. The callbacks
defined in "on-the-fly" context, for some reason, must be written as
strings and then injected into the property's logic. JScript has the
toString() method, which converts easily code blocks into strings.

The following Pythoin code works well. Functions are written directly
as strings, so no problem. It does exactly the same property as the
example above, except that it is being done "on-the-fly" instead of
through a plugin.


# Instantiate the Applicaiton object,
# for running command in the host application
xsi = Application

# Define callback functions
sOnInit = """def OnInit():
   pass"""

sMyButtonOnClicked = """def myButton_OnClicked():
   print 'hello world'"""

# Create plain custom property
oProperty = xsi.activesceneroot.addproperty( 'CustomProperty', False )

# Add parameters
oParameter = oProperty.addparameter3( 'myparameter', 8, '' )

# Get property layout
oLayout = oProperty.PPGLayout
oLayout.Clear()

# Set the layout environment
oLayout.Language = 'Python'

# Inject logic into the layout.
# Join all functions defined in strings.
oLayout.Logic = '\n'.join( [sOnInit, sMyButtonOnClicked] )

# Create buttons
oLayout.additem( oParameter.scriptname, oParameter.scriptname )
oLayout.addbutton( 'myButton' )

# Inspect the property
xsi.inspectobj( oProperty )



Now back to the actual problem.

In the task I'm currently having, I have to dynamically create a
certain number of layout elements along its logic. The number of
elements to create changes from one execution to the next, as it is
driven by the user input. Since properpty plugins do not support such
dynamic creation, my only solution is with the "on-the-fly" approach.

Now what I'd like to do is to create "real" functions, not strings,
and convert them into strings for logic injection.



Thanks!
Bernard
_______________________________________________
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor

Reply via email to