[Closed] Adding an array to a node via custom attributes
I’m attempting to add an array to a node via custom attributes, however, this type is not supported as a custom attribute:
“– Compile error: Unrecognized parameter type: Array”
What’s a workaround to this?
here is a list of supported arrays:
#floatTab
#intTab
#indexTab
#colorTab
#rgbTab
#frgbaTab
#point3Tab
#point4Tab
#boolTab
#angleTab
#percentTab
#worldUnitsTab
#matrix3Tab
#stringTab
#filenameTab
#colorChannelTab
#timeTab
#radiobtnIndexTab
#materialTab
#texturemapTab
#bitmapTab
#nodeTab
[i]#maxObjectTab
[/i]see mxs help for details -> Scripted Plug-in Clauses
Let me explain what I’m trying to do:
- merge a max file with #select enabled
- put $ into an array variable
- apply that array variable to a node via customAttributes
(3) is what I can’t get to work.
So far, I’ve tried converting the array to a string, and then sending that string to a function that does some character comparison and returns the string as an array… that works great – except that the string value type has a maximum length, and part of the array gets dropped in the casting process.
I’m going to try a different approach: when the max file is merged in and cast as an array, loop thru the array collecting the node.name properties into a comma delimited string. then later pass this string to the stringToArray function, which returns an array with values that will work with the command ‘getNodeByName’. This way, I can store the mergedNodes as a comma delimited string on another node, and convert that string to an array whenever I need to. Only collecting the node.name should reduce the total size of the array to a value that can be reliably cast as a string.
Or, another approach would be to write a function that dynamically adds strings as customAttributes to a node. Where you could pass an array as a parameter, and then the function distributes each element to a string custom attribute on the node. <This method scales with character complexity, whereas the above method does not.
DenisT,
The #nodeTab, and #maxObjectTab arrays seem to be what I want. Although I’m not sure I can create them in this context:
customAttributes = attributes objectData
(
rollout paramsRollout "Tiny IDs"
(
--some UI elements and stuff
)
parameters main rollout:paramsRollout
(
--some values
associatedNodes type:#string default:""
)
)
custAttributes.add $ customAttributes
Do you know of an easier way to do this?
here is a sample how these things to do:
global nodeTabAttr = attributes nodeTabAttr attribID:#(0x1cabedab, 0x5551de47)
(
parameters main rollout:main
(
nodes type:#nodeTab tabSize:0 tabSizeVariable:on
on nodes tabChanged do
(
this.main.nodes_count.text = (nodes.count as string)
)
)
rollout main "Nodes"
(
edittext nodes_count "Nodes Count: " text:"0" fieldwidth:40 readonly:on
on main open do nodes_count.text = (this.nodes.count as string)
)
)
delete objects
d = dummy name:"Node_Holder"
for k=1 to 10 do box()
custAttributes.add d nodeTabAttr baseobject:on
for obj in objects where obj != d do append d.nodes obj
select d
max modify mode
/*
--
deleteitem d.nodes 1
--
append d.nodes objects[3]
--
d.nodes = #(objects[4],objects[5])
*/
i don’t have time to explain… so see the mxs help.
Thank you denis! I’ll be studying that code.
But, I ran into an interesting issue (that throws an unknown exception) that I’m able to reproduce again and again. Here is a code snippet that demonstrates this:
(
fn createCA includeNodesArray:false copyCharID:"init" theNode: =
(
if includeNodesArray == true then
(
customAttributes = attributes objectData
(
rollout paramsRollout "Tiny IDs"
(
edittext charFileAddressEt text:copyCharID fieldWidth:145 height:18 pos:[5,25] type:#string enabled:false
on charFileAddressEt changed theState do $.objectData.tinyCharID = charFileAddressEt.text
)
parameters main rollout:paramsRollout
(
tinyCharID type:#string ui:charFileAddressEt default:""
)
)
custAttributes.add theNode customAttributes
) else (
customAttributes = attributes objectData
(
rollout paramsRollout "Tiny IDs"
(
edittext charFileAddressEt text:"init" fieldWidth:145 height:18 pos:[5,25] type:#string enabled:false
on charFileAddressEt changed theState do $.objectData.tinyCharID = charFileAddressEt.text
)
parameters main rollout:paramsRollout
(
tinyCharID type:#string ui:charFileAddressEt default:"init"
)
)
custAttributes.add theNode customAttributes
)
)--end fn
local myBox = Box lengthsegs:1 widthsegs:1 heightsegs:1 length:20 width:20 height:20 mapcoords:on pos:[0,0,0] isSelected:off
createCA includeNodesArray:true copyCharID:"someAddress" theNode:myBox
print "complete"
)
/*
Now, select the box and pull up the modify panel. Max should throw an unknown system exception.
*/
Run the code. Then, select the box and pull up the modify panel. On my comp, max throws an unknown system exception, and the customAttributes that were added don’t appear.
Is there a flaw in my code above that is causing this to happen?
If I could get the above code to work, I could add an array to a node by creating a dropdown UI on the node and passing the array to the dropdown.items. The array should be recoverable by querying the node.objectData.paramsRollout.dropdown.items.
But I have no idea why max is throwing an unknown exception in this case.
Anyone have a guess?
the line
on charFileAddressEt changed theState do $.objectData.tinyCharID = charFileAddressEt.text
causes the problem.
use this instead of $…
but you don’t need to do it because the ui control is linked to the parameter.
denis – i tried commenting out those lines and running the script again.
max still throws an unknown exception when you select the modify tab.
so, i investigated further:
(
fn createCA includeNodesArray:false copyCharID:"init" theNode: =
(
if includeNodesArray == true then
(
customAttributes = attributes objectData
(
rollout paramsRollout "Tiny IDs"
(
edittext charFileAddressEt text:copyCharID fieldWidth:145 height:18 pos:[5,25] type:#string enabled:false
)
parameters main rollout:paramsRollout
(
tinyCharID type:#string ui:charFileAddressEt default:""
)
)
custAttributes.add theNode customAttributes
) else (
customAttributes = attributes objectData
(
rollout paramsRollout "Tiny IDs"
(
edittext charFileAddressEt text:"init" fieldWidth:145 height:18 pos:[5,25] type:#string enabled:false
)
parameters main rollout:paramsRollout
(
tinyCharID type:#string ui:charFileAddressEt default:"init"
)
)
custAttributes.add theNode customAttributes
)
)--end fn
local myBox = Box lengthsegs:1 widthsegs:1 heightsegs:1 length:20 width:20 height:20 mapcoords:on pos:[0,0,0] isSelected:off
createCA includeNodesArray:true copyCharID:"someAddress" theNode:myBox
local myBox2 = Box lengthsegs:1 widthsegs:1 heightsegs:1 length:20 width:20 height:20 mapcoords:on pos:[0,50,0] isSelected:off
createCA includeNodesArray:false copyCharID:"someAddress" theNode:myBox2
print "complete"
)
/*
Now, select either box and pull up the modify panel. Max should throw an unknown system exception, if you select the first box, box001.
*/
Run the code, select box002. Open the modify tab. Everything is as normal.
Now, select box001 (@ origin). Open the modify tab, or if you have it open already: unknown system exception.
Here's the difference in the two states in the code above:
edittext charFileAddressEt text:copyCharID
edittext charFileAddressEt text:"init"
Both are passed strings. What's going on here?
createCA includeNodesArray:true copyCharID:"someAddress" theNode:myBox2
This is how I'm passing the string to the copyCharID variable contained within the function.
As far as my understanding of maxscript goes, there is no difference between a variable and it's contents, correct? I mean to say that copyCharID literally equals the string "someAddress". I would expect the edittext's text parameter would accept either representation of that string, but it would appear that this is not the case.
an optional parameter can be passed a string, right?
Here is a script that the listener does not like:
fn createCA aString:"aString" =
(
customAttributes = attributes objectData
(
rollout paramsRollout "..."
(
edittext Et text:aString fieldWidth:145 height:18 pos:[5,25] type:#string enabled:true
)
parameters main rollout:paramsRollout
(
aString type:#string ui:Et default:aString
)
)
)
Listener says:
-- Runtime error: Plug-in not active, unable to access plug-in local or parameter: aString
Here it is outside of the function with a namespace:
(
aString="something"
customAttributes = attributes objectData
(
rollout paramsRollout "..."
(
edittext Et text:aString fieldWidth:145 height:18 pos:[5,25] type:#string enabled:true
)
parameters main rollout:paramsRollout
(
aString type:#string ui:Et default:aString
)
)
)
Same error. It’s an interesting roadblock.
Just to say that am not read the whole thread, but theck this one:
aString type:#string ui:Et default:[b]aString[/b]
Aha! Here is code that works as expected, and since it’s an array that is being passed as a parameter, it solves my problem!
clearListener()
(
anArray=#("aFileAddress","aFileAddress","aFileAddress")
customAttributes = attributes objectData
(
rollout paramsRollout "..."
(
dropdownlist mydd "aDropdown" items:anArray
)
parameters main rollout:paramsRollout
(
anInteger type:#integer ui:mydd default:1
)
)
local myBox = Box lengthsegs:1 widthsegs:1 heightsegs:1 length:20 width:20 height:20 mapcoords:on pos:[0,50,0] isSelected:off
custAttributes.add myBox customAttributes
)
The dropdown UI element items parameter accepts the array variable without exception.
I wonder why the string version fails?
In a cruel twist of fate, another system exception happens trying to get the items from the dropdown:
clearListener()
(
anArray=#("aFileAddress","aFileAddress","aFileAddress")
customAttributes = attributes objectData
(
rollout paramsRollout "..."
(
dropdownlist mydd "aDropdown" items:anArray
)
parameters main rollout:paramsRollout
(
anInteger type:#integer ui:mydd default:1
)
)
local myBox = Box lengthsegs:1 widthsegs:1 heightsegs:1 length:20 width:20 height:20 mapcoords:on pos:[0,50,0] isSelected:off
custAttributes.add myBox customAttributes
print myBox.objectData.paramsRollout.mydd.items
)
The listener says:
OK
-- Error occurred in anonymous codeblock
-- Frame:
-- anArray: #("aFileAddress", "aFileAddress", "aFileAddress")
-- myBox: $Box001
** system exception **
I can add an array to a dropdown UI element, but I can’t get the array back?
I’m confuzzeled. :shrug:
However, I do not want to declare a global.
global nodeTabAttr = attributes nodeTabAttr attribID:#(0x1cabedab, 0x5551de47)
( ...
I want a node to represent a collection of objects, and I’d like to be able to retrieve that collection from the node in the scene with a syntax such as <node>.objectData.paramsRollout.aUIelement.items. Is there another manner in which I could “attach” an array to a node in max? Ideally, I’d like to be able to use this syntax: <node>.objectData.anArray, but I cannot.
Is there a .net spell that can kill this dragon?
you are trying to get access to the rollout which is not created yet.
so it should be:
(
anArray = #("aFileAddress","aFileAddress","aFileAddress")
ca = attributes objectData
(
rollout paramsRollout "..."
(
dropdownlist mydd "aDropdown" items:anArray
)
parameters main rollout:paramsRollout
(
anInteger type:#integer ui:mydd default:1
)
)
local myBox = Box lengthsegs:1 widthsegs:1 heightsegs:1 length:20 width:20 height:20 mapcoords:on pos:[0,50,0] isSelected:off
custAttributes.add myBox ca
select myBox
max modify mode [color=YellowGreen]-- now the rollout was created the first time[/color]
print myBox.objectData.paramsRollout.mydd.items
)
but i would do it another way:
fn applyObjectData node default:1 arr:#() = if isvalidnode node do
(
str = "attributes objectData
(
parameters params rollout:params
(
index type:#integer ui:list default:%
)
rollout params \"Parameters\"
(
dropdownlist list \"The List:\" items:%
)
)
"
ss = stringstream ""
format str default (with printallelements on arr as string) to:ss
objectData = execute (ss as string)
free ss
custAttributes.add node objectData baseobject:on
)
delete objects
b = box name:"the_holder"
applyObjectData b default:2 arr:#("One", "Two", "Three", "Four")
select b
max modify mode
/*
--
b.index = 3
*/