Below is an example demonstrating how you can dynamically create sliders for specific properties associated with a given node (presented in the context of the node within the interface).
// Define an anonymous function; // serves as our main loop, // limits the scope of variables (function( bDebug ){ // Define a 'static' variable that holds whether we can use Function.scriptConnect() var s_bScriptConnect = (typeof( Function.scriptConnect ) == "function"); // Define a 'static' variable that holds whether we can use Global::connect() to // define 'this' within a function; i.e., 4.15.0.18 or newer var s_bGlobalMemberFuncConn = s_bScriptConnect ? App.version64 >= 0x0004000f00000012 : false; // Define a 'static' map of property-slider pairs var s_oSliderMap = {}; /*********************************************************************/ // String : A function for retrieving a translation if one exists function text( sText ) { // If the version of the application supports qsTr() if( typeof( qsTr ) != "undefined" ){ // Return the translated (if any) text return qsTr( sText ); } // Return the original text return sText; }; /*********************************************************************/ // Array<DzProperty> : A function for getting a list of the properties in a group function getGroupProperties( oGroup, bTraverse, bRecurse ) { // Declare an array to hold properties var aProperties = []; // If a group is not passed in if( !oGroup ){ // We are done, return an empty array return aProperties; } // Get the number of proeprties in the group var nProperties = oGroup.getNumProperties(); // Pre-size the properties array aProperties = new Array( nProperties ); // Iterate over the properties, setting each element in the array for( var i = 0; i < nProperties; i += 1 ){ // Assign the property to the position in the array aProperties[ i ] = oGroup.getProperty( i ); } // If we are recursing if( bRecurse ){ // Concatenate the properties array from child groups aProperties = aProperties.concat( getGroupProperties( oGroup.getFirstChild(), true, bRecurse ) ); } // If we are traversing if( bTraverse ){ // Concatenate the properties array from sibling groups aProperties = aProperties.concat( getGroupProperties( oGroup.getNextSibling(), bTraverse, bRecurse ) ); } // Return the array of properties return aProperties; }; /*********************************************************************/ // Array<DzProperty> : A function for getting the list properties for an element function getElementProperties( oElement, bTraverse, bRecurse ) { // Get the property group tree for the element var oPropertyGroupTree = oElement.getPropertyGroups(); // If the application version is 4.9.4.101 or newer and we want all properties if( App.version64 >= 0x0004000900040065 && bTraverse && bRecurse ){ // Return the properties for the element return oPropertyGroupTree.getAllProperties(); } // Get the first group in the tree var oPropertyGroup = oPropertyGroupTree.getFirstChild(); // Return the properties for the element return getGroupProperties( oPropertyGroup, bTraverse, bRecurse ); }; /*********************************************************************/ // DzProperty : A function for finding a property associated with an element function findElementProperty( oElement, sProperty, bUseLabel ) { // Whether or not to use optimizations; 4.7.1.44 or newer var bUseOptimization = (App.version64 >= 0x000400070001002c); // Declare a working variable var oProperty; // If the application version is 4.7.1.44 or newer and we are not using // the label to find, or the application version is 4.11.0.166 or newer if( (bUseOptimization && !bUseLabel) || App.version64 >= 0x0004000b000000a6 ){ // Get the property group tree for the element var oPropertyGroupTree = oElement.getPropertyGroups(); // If we are using the label if( bUseLabel ){ // Attempt to find the property oProperty = oPropertyGroupTree.findPropertyByLabel( sProperty ); // If we are not using the label } else { // Attempt to find the property oProperty = oPropertyGroupTree.findProperty( sProperty ); } // If we found a property if( oProperty ){ // We are done, return it return oProperty; } // Otherwise } else { // Get the properties of the element var aProperties = getElementProperties( oElement, true, true ); // Iterate over the properties for( var i = 0; i < aProperties.length; i += 1 ){ // Get the 'current' property oProperty = aProperties[i]; // If we are using the label if( bUseLabel ){ // If the label of the property is the one we are looking for if( oProperty.getLabel() == sProperty ){ // We are done, return it return oProperty; } // If we are not using the label } else { // If the name of the property is the one we are looking for if( oProperty.name == sProperty ){ // We are done, return it return oProperty; } } } } // Declare working variables var oChild; // Iterate over the child elements for( var i = 0, nChildren = oElement.getNumElementChildren(); i < nChildren; i += 1 ){ // Get the 'current' child element oChild = oElement.getElementChild( i ); // Get the property from the child oProperty = findElementProperty( oChild, sProperty, bUseLabel ); // If we are using a version with optimizations if( bUseOptimization ){ // If we have a property if( oProperty ){ // We are done, return it return oProperty; } // Otherwise } else { // If we are using the label if( bUseLabel ){ // If the label of the property is the one we are looking for if( oProperty.getLabel() == sProperty ){ // We are done, return it return oProperty; } // If we are not using the label } else { // If the name of the property is the one we are looking for if( oProperty.name == sProperty ){ // We are done, return it return oProperty; } } } } return null; }; /*********************************************************************/ // void : A function for handling the editEnd() signal from a slider // 'this' is expected to be an instance of DzFloatSlider, or DzIntSlider function handleSliderEditEnd() { // If the 'this' object doesn't have a 'name' member if( this["name"] == undefined ){ // Record the error print( "'this' does not have a 'name' member!" ); // We are done... return; } // If the 'this' object doesn't have a 'value' member if( this["value"] == undefined ){ // Record the error print( this.name, "does not have a 'value' member!" ); // We are done... return; } // Get the id that was encoded into the name of the slider var sId = this.name.split( "__" )[ 0 ]; // Get the node and property members var oMapItem = s_oSliderMap[ sId ]; var oNode = oMapItem[ "node" ]; var oProperty = oMapItem[ "property" ]; // Do something with the values of the member(s) we verified to exist print( "Adjust", oProperty.getLabel(), "on", oNode.getLabel(), "by", this.value - oProperty.getValue() ); }; /*********************************************************************/ // void : A function for initializing a slider with common settings function initSlider( wSlider, sId, sName, sLabel ) { // Configure common settings wSlider.labelVisible = true; wSlider.textEditable = true; wSlider.name = String("%1__%2").arg( sId ).arg( sName ); wSlider.label = sLabel; // Connect the 'editEnd' signal on the slider to the // 'handleSliderEditEnd' function in a way that sets the // 'this' object in the function to the slider // If we can use Global::connect( sender, "signal", thisObject, slot ) syntax if( s_bGlobalMemberFuncConn ){ connect( wSlider, "editEnd()", wSlider, handleSliderEditEnd ); // Otherwise, if we can use the sender.signal.scriptConnect( thisObject, slot ) syntax } else if( s_bScriptConnect ){ wSlider.editEnd.scriptConnect( wSlider, handleSliderEditEnd ); // Otherwise, fall back to the deprecated syntax } else { // The first argument provides the 'this' object within // the function, the second argument is the function wSlider.editEnd.connect( wSlider, handleSliderEditEnd ); } }; /*********************************************************************/ // DzFloatSlider : A function for creating a float slider function createFloatSlider( wParent, nId, sName, sLabel ) { // Create a float slider widget var wSlider = new DzFloatSlider( wParent ); // Initialize the slider initSlider( wSlider, nId, sName, sLabel ); // Return the slider return wSlider; }; /*********************************************************************/ // DzFloatSlider : A function for creating a float slider for a property function createFloatPropertySlider( wParent, nId, oProperty ) { // Get the name and label of the property var sName = oProperty.name; var sLabel = oProperty.getLabel(); // Create the float slider var wSlider = createFloatSlider( wParent, nId, sName, sLabel ); // Configure the slider to match the property wSlider.min = oProperty.getMin(); wSlider.max = oProperty.getMax(); wSlider.clamped = oProperty.isClamped(); wSlider.sensitivity = oProperty.getSensitivity(); wSlider.displayAsPercent = oProperty.getDisplayAsPercent(); wSlider.value = oProperty.getValue(); // Return the slider return wSlider; }; /*********************************************************************/ // void : A function for creating float sliders for properties on a node function createNodePropertySliders( wParent, oNode, aPropertyNames ) { // Declare local working variables var sId; var oProperty; var wSlider; // Iterate over the property names for( var i = 0, nNames = aPropertyNames.length; i < nNames; i +=1 ){ // Find the property on the node oProperty = findElementProperty( oNode, aPropertyNames[ i ], false ); // If the property was not found if( !oProperty ){ // Next!! continue; } // Create a unique (reproducible) id sId = App.createDigest( [ oNode.getLabel(), oProperty.getLabel() ] ); // Create the slider for the property wSlider = createFloatPropertySlider( wParent, sId, oProperty ); // Update the map s_oSliderMap[ sId ] = { "node" : oNode, "property" : oProperty, "slider" : wSlider }; } }; /*********************************************************************/ // DzFloatSlider : A function for creating a float slider for a property function applyChanges() { // Declare local working variables var sId; var oMapItem, oProperty; var wSlider; // Get the IDs for the property-slider map var aIds = Object.keys( s_oSliderMap ); // Start collecting changes beginUndo(); // Iterate over the IDs for( var i = 0, nIds = aIds.length; i < nIds; i += 1 ){ sId = aIds[ i ]; oMapItem = s_oSliderMap[ sId ]; oProperty = oMapItem[ "property" ]; wSlider = oMapItem[ "slider" ]; oProperty.setValue( wSlider.value ); } // Finish collecting changes and add the undo to the stack acceptUndo( text( "Node Property Slider Test" ) ); }; /*********************************************************************/ // Declare working variables var wSlider, wGroupBox; var oNode, oProperty; // Get the list of selected nodes var aNodes = Scene.getSelectedNodeList(); // Get the number of selected nodes var nNodes = aNodes.length; // If no nodes are selected if( nNodes < 1 ){ // Inform the user MessageBox.information( text( "A node must be selected to continue." ), text( "Selection Error" ), text( "&OK" ) ); // We are done... return; } // Define the list of property names to create slider for var aPropertyNames = [ "XRotate", "YRotate", "ZRotate" ]; // Create a basic dialog var oDlg = new DzBasicDialog(); // Iterate over the nodes for( var i = 0; i < nNodes; i +=1 ){ // Get the 'current' node oNode = aNodes[ i ]; // Create a group box with a vertical box layout for the node wGroupBox = new DzVGroupBox( oDlg ); wGroupBox.title = oNode.getLabel(); // Create the sliders for the named properties; if they exist createNodePropertySliders( wGroupBox, oNode, aPropertyNames ); // Add the group box to the dialog oDlg.addWidget( wGroupBox ); } // Launch the dialog, and if the user cancels if( !oDlg.exec() ){ // We are done... return; } // Apply the changes from the map applyChanges(); // Finalize the function and invoke })( true );