[Closed] Get property type
Okay so this is probably really simple and Im missing where its stated in the maxscript help!
Anyways, I got the selected object (I check to make sure the selection isnt > 1) now that being $ I can get the classof that object. From there I can find all the properties that object has using getPropNames $ which gives me all the property names in an array.
What Im looking to do is find out what type those properties are, bool, float, int from that array so I can create a rollout with the rollout creator dynamically. If its a bool it’ll make a checkbox, if its float or int it’ll create a spinner with the correct type etc.
Now ShowClass will show the properties with their associated type but Im unsure if that would be useful as Id have to go in and cut up some strings and whatnot even if that returns to a variable I can use to do those operations on.
Basically all I need is a name for the property type :curious:
something simple like
classof (getProperty <object> <prop name>)
should work
Keep in mind that this only works for values that actually exist.
E.g.
$.modifiers[1]
Displace:Displace
getProperty meditmaterials[1] #diffuseMap
undefined
classOf (getProperty meditmaterials[1] #diffuseMap)
UndefinedClass
So you can’t use that to dynamically create a mapButton as all the script tells you is that the value is undefined – not what the expected value would be.
Here’s an alternative:
-- could change this to use by-reference parameters to deal with the two array results
fn getProps obj = (
propString = stringStream ""
showproperties obj to:propString
propString = propString as string
propArray = filterString propString "
"
if (propArray.count == 0) then ( return #(#(),#()) )
propNamesArray = #(); propNamesArray[propArray.count] = undefined
propTypesArray = #(); propTypesArray[propArray.count] = undefined
for i = 1 to propArray.count do (
prop = propArray[i]
prop = filterString prop ":"
propNamesArray[i] = (subString (sfs.lib.strTrim (filterString prop[1] " ")[1]) 2 -1) as name
if (prop.count == 2) then ( propTypesArray[i] = sfs.lib.strTrim prop[2] )
)
#(propNamesArray,propTypesArray)
)
fn getPropType obj prop = (
props = getProps obj
propNames = props[1]
propTypes = props[2]
propIndex = findItem propNames prop
if (propIndex != 0) then ( propTypes[propIndex] )
else ( false )
)
getPropType $.modifiers[1] #map
"texturemap"
Note that there is a special set of types of parameter values that end in ‘array’… these are of class ArrayParameter and basically work like an array and would have to be accessed as such to enumerate the actual parameters; this applies to the above script as well as Gravey’s method. Each ArrayParameter can only be an array with parameters of the same type, so the above code should tell you what type of data is in the array… e.g. texturemap, percent (float), float, etc.
Also note that some parameters may have spaces in them… it shouldn’t happen, but I’ve seen it happen in at least (older versions of?) DreamScape, parameter “.Pixel Sampler”. The space should be removed for proper access.
==================================================
Edit: just a .NET thingy that makes use of some of this… it doesn’t access the properties, so the ‘spaces in parameter names’ is not dealt with.
Just enter a target (standard script code… e.g ‘$’ or ‘$.material’, etc.) and it will make a nice tree item for that target with all of the parameter names, their values, their value types ( in parentheses for types derived with the above code, curly braces for classOf() ), and class hierarchy if it’s a maxwrapper. The tree branches out for any parameters that have subparameters as well as for ArrayParameters.
fn classGetHierarchy theClass = (
local classHierarchy = #(theClass)
while ((theClass = classOf theClass) != classHierarchy[1]) do (
insertItem theClass classHierarchy 1
)
return classHierarchy
)
try(destroyDialog treeview_rollout)catch()
rollout treeview_rollout "Properties Tree" width:512 height:540 (
dotNetControl tv "TreeView" width:500 height:500 align:#center
edittext edt_targ "target" across:3
button btn_add "add"
button btn_clear "clear"
fn getProps obj = (
propString = stringStream ""
showproperties obj to:propString
propString = propString as string
propArray = filterString propString "
"
if (propArray.count == 0) then ( return #(#(),#()) )
propNamesArray = #(); propNamesArray[propArray.count] = undefined
propTypesArray = #(); propTypesArray[propArray.count] = undefined
for i = 1 to propArray.count do (
prop = propArray[i]
prop = filterString prop ":"
propNamesArray[i] = (subString (sfs.lib.strTrim (filterString prop[1] " ")[1]) 2 -1) as name
if (prop.count == 2) then ( propTypesArray[i] = sfs.lib.strTrim prop[2] )
)
if (isKindOf obj node) then ( join propNamesArray (getPropNames node) )
#(propNamesArray,propTypesArray)
)
fn clearTV = (
tv.nodes.clear()
)
fn hasProperties obj = (
try (
local props = getPropNames obj
classOf props == Array
)
catch ( false )
)
fn addProps node obj i: = (
local propData = getProps obj
local propNames = propData[1]
local propTypes = propData[2]
for prop in propNames do (
local propValue = getProperty obj prop
local propValueStr
if (classOf propValue == string) then ( propValueStr = "\"" + propValue + "\"" )
else if (classOf propValue == ArrayParameter) then ( propValueStr = "[arrayParameter]" )
else ( propValueStr = propValue as string )
local propType = undefined
local propTypeStr = ""
-- if ((propValue == undefined) OR (classOf propValue == ArrayParameter)) then (
local propIndex = findItem propNames prop
local propType = if (propIndex == 0) then ( undefined ) else ( propTypes[propIndex] )
if (propType == undefined) then (
propType = (classOf propValue) as string
propTypeStr = " {" + propType + "}"
)
else (
propTypeStr = " (" + propType + ")"
)
-- )
local classHierarchy
local classHierarchyStr = ""
if (isKindOf propValue maxWrapper) then (
classHierarchy = classGetHierarchy propValue
if (classHierarchy.count >= 2) then (
for i = (classHierarchy.count - 1) to 1 by -1 do (
classHierarchyStr += classHierarchy[i] as string + (if (i > 1) then ( " > " ) else ( ""))
)
)
else ( classHierarchyStr = classHierarchy[1] as string )
)
if (classHierarchyStr != "") then ( classHierarchyStr = " :: " + classHierarchyStr )
newNode = node.nodes.add ((prop as string) + " = " + propValueStr + propTypeStr + classHierarchyStr)
if (hasProperties propValue) then ( addProps newNode propValue )
if (classOf propValue == ArrayParameter) then (
propTypeStr = subString propTypeStr 1 ((findString propTypeStr "array") - 2) + ")"
for i = 1 to propValue.count do (
propValueStr = propValue[i] as string
-- horrible code copy/paste that should be a function
local classHierarchy
local classHierarchyStr = ""
if (isKindOf propValue[i] maxWrapper) then (
classHierarchy = classGetHierarchy propValue[i]
if (classHierarchy.count >= 2) then (
for i = (classHierarchy.count - 1) to 1 by -1 do (
classHierarchyStr += classHierarchy[i] as string + (if (i > 1) then ( " > " ) else ( ""))
)
)
else ( classHierarchyStr = classHierarchy[1] as string )
)
if (classHierarchyStr != "") then ( classHierarchyStr = " :: " + classHierarchyStr )
-- /horrible code copy/paste
local apNode = newNode.nodes.add ((prop as string) + "[" + i as string + "] = " + propValueStr + propTypeStr + classHierarchyStr)
if (hasProperties propValue[i]) then ( addProps apNode propValue[i] )
-- apNode.Expand()
)
)
-- newNode.Expand()
)
)
on tv doubleClick arg do (
hitNode = tv.GetNodeAt (dotNetObject "System.Drawing.Point" arg.x arg.y)
if hitNode != undefined do ( print hitNode )
)
fn addInfo obj = (
newNode = tv.nodes.add (obj as string)
addProps newNode obj
newNode.expand()
)
on btn_add pressed do (
-- addInfo (execute edt_targ.text)
try (addInfo (execute edt_targ.text)); catch()
)
on btn_clear pressed do (
clearTV()
)
)
createDialog treeview_rollout
Any node you specify as a target is ‘special’ as it adds the common properties for ‘node’ (name, material, target, etc.) although it can’t derive the expected type automatically. So e.g. ‘target’ is “undefined {UndefinedClasS}” unless it actually has a target. Can’t do much about that one other than per-case code.
Ahhh very kewl, this alternative you posted seems to be similar to what I was suggesting with the ShowClass. I didnt realize however there might be problems accessing some properties, I am making sure that the property exists in some fashion though by using getPropNames on the selected object.
I would assume if a diffuse map was present for a material it would also display, then again $ seems to return only the viewport selected and not the material editor selected. If a material is assigned to selected in the viewport I would assume I could access that material as a property and find the type of that property then work my way down to the maps to see which exist using getPropsName.
For eg
$.material
01 - Default:Standard
classOf (getProperty $ "material")
Standardmaterial
getPropNames Standardmaterial
#(#shaderType, #wire, #twoSided, #faceMap, #faceted, #shaderByName, #opacityType, #opacity, #filterColor, #filterMap, #opacityFallOffType, #opacityFallOff, #ior, #wireSize, #wireUnits, #applyReflectionDimming, #dimLevel, #reflectionLevel, #sampler, #samplerQuality, ...)
and...
classOf (getProperty Standardmaterial "wire")
-- Error occurred in anonymous codeblock
-- Frame:
-- Unknown property: "wire" in Standardmaterial
getProperty Standardmaterial "opacity"
-- Unknown property: "opacity" in Standardmaterial
That is very strange, perhaps you are correct and not just for properties that dont exist. Unless theres something Im doing incorrectly :eek:
Edit:
classOf (getProperty $.material "wire")
BooleanClass
Ahhh
In your second example that is returning an unknown property (ah, you’ve edited it!), that is because you are attempting to get the value of a class property, not an instance (an object that has been created from a class) property.
All classes have properties, obviously, but as the class is not instantiated as an instance (a real object that you can work on) the set/getProperty methods won't work:
mat = $.material -- get the selected object's material
01 - Default:Standard
matClass = (classOf $.material) -- get the class of the selected object's material
StandardMaterial
getProperty mat #wire -- get the current value of the "wire" property of the selected object's material
true
getProperty matClass #wire -- get the current value of the "wire" property of the selected object's material class, StandardMaterial
Unknown property: "wire" in Standardmaterial
This last example won't work, as you are trying to access properties on a non-instantiated class!
Hope that helps,
Dave
Ahh that is helpful, that means if I have the properties after using getPropsNames and I have the object I can just use classOf object.property. I guess I shouldnt make the assumption types are different to classes but it does vary from language to language as far as Im aware, like for eg in C# you could use String or string where ones a type and the other is a class/object? Correct me if im wrong
Now I know this though I see the full use of classOf