[Closed] Best setup for complex dynamic rollout
Hi,
I am currently working on a dynamic UI and would like to get some opinions on what the best approach is for this.
Lets say, based on the current selection, a listing of that selection is generated in a rollout with specific buttons and therefore specific functionalities for each listed object. I started to script it with executing a stringstream but it got really complicated quite fast, I am having problems to pass data to the rollout and it is really slow. Currently I tested my script only with 3 objects or so, but it might easily be used in production with around 20 objects that should be listed and modified with their correlating buttons in the rollout.
Is a stringstream the way to go and I just have to make it work or should I rather go with a dotNet listing? I used dotnot just very superficially so far and I can't really judge its complexity for a task like the one I need.
Thanx!
I have previously created rollouts dynamically by executing stringstreams and I’d say it’s the way to go. It has always been really really fast for me. Perhaps post some example code or at least more details on your script like what functionality you want for what kind of objects and why it’s not working for you.
As for dotnet, based on your problem I’d say that it’s not needed unless you want to use dotnet controls in your dynamic rollout
For a dynamic rollout the stringstream should be the way, probably the only way. Why is it slow, do you make sure all functionality is not being build as well, you should have a struct or some global functions which the buttons change handlers call to. So only make sure to dynamicly build the UI and changehandlers and the main functionality should be build seperatly. Are you also updating the dynamic rollout frequently? Constantly pushing the string through execute can be very slow.
-Johan
Look up RolloutCreator in the MaxScript docs. I’ve used it whenever I needed to create dynamic UI’s and it’s very nice. Also, definitely do what JHN said and put your non-UI code inside functions, possibly in a global struct. Trying to maintain that code inside a set of strings will drive you crazy.
Hi guys,
thanks for suggesting to go with stringstreams. I did make everything work that way and had something to show yesterday evening:-)… but I think I created some nasty code and now I would like to make it pretty.
First of all, I have nearly all my code within the stringstream. The problem is that I need to access dynamically created UI items, like a lable, with the functions. Therefore I am creating a version of a function for each UI item. Here an example (which I hope is understandable).
(
(...)
arMergedObj = #()
rolloutSS = stringStream ""
(...)
if iObjectCount > 1 do (
(...)
format "
button btn_allObjectsToHires \"All Objects to Hires\" pos:[12,%] width:110 height:13
(...)
" tmpHeight1 to:rolloutSS
)
if iObjectCount != 0 then (
for i=1 to iObjectCount do
(
(...)
val_model = tmpAddMe + 60
val_modelText = tmpAddMe +60
val_displayText = tmpAddMe +84
val_proxyPath = tmpAddMe +144
format "label lbl_model_% \"Model:\" pos:[12,%] width:41 height:15
" i val_model to:rolloutSS
format "label lbl_modelText_% \"%\" pos:[60,%] width:216 height:14
" i arMergedObj[i].name val_modelText to:rolloutSS
format "label lbl_displayText_% \"%\" pos:[60,%] width:120 height:14
" i str_proxyDisplay val_displayText to:rolloutSS
format "label lbl_proxyPath_% \"%\" pos:[12,%] width:500 height:50
" i str_proxyPath val_proxyPath to:rolloutSS
format ("
--fnToggleObjects---------------------------------------------------
fn fnToggleObjects_% superDad = (
(...)
lbl_displayText_%.text = sSwitchTo
(...)
") i ito:rolloutSS
format ("
--fnToggling---------------------------------------------------
fn fnToggling_% superDad meshes = (
(...)
fnToggleObjects_% superDad
(...)
)
") i i to:rolloutSS
------------------------------------------------------------------------------------------------------------------UI-----------------------------------
format ("
on btn_toggleObjects_% pressed do
(
(...)
fnToggling_% superDad false
)
") i i i to:rolloutSS
)-- end loop
) --end: if iObjectCount == 0
------------------------------------------------------------------------------------------------------------------
format (" on btn_allObjectsToHires pressed do ( ") to:rolloutSS
for i=1 to arMergedObj.count do (
format ("
(...)
if superDad.objectDataCA.bProxyDisplay == true do fnToggling_% superDad false
") arMergedObj[i].name i to:rolloutSS
)
format (")
") to:rolloutSS
------------------------------------------------------------------------------------------------------------------UI-----------------------------------
format ")
" to:rolloutSS
createDialog (execute(rolloutSS as string))
rolloutSS = undefined
)
Like I said. I am not sure how to separate the functionality which heavily makes use of the dynamically created UI items.
thanx
Can’t do much about the on “<control>_UID” event handlers, but the functions you call – you could pass them your UID counter as a parameter… that way you only need 1 function.
I hope you can read my code above…I was just about to format it some more when I accidentally hit some keys on my keyboard which lead to posting my text;-)…
Anyway, another question I have: how do I change the default Maxscript Editor to not making the background color of multi-line strings pink? I do like pink, but that color is just too much to stare on the whole day…
Thanx
Have a look at “MAXScript Editor – Customizing Syntax Color Schemes” – basically you just need to edit the maxscropt properties file (Tools > Open MAXScript.properties), and replace the appropriate color definition. In your case:
-- change this
; style.MAXScript.6=fore:#000000,$(font.monospace),back:#E0C0E0,eolfilled
-- to, for example, this (standard string formatting without the background color change, etc.)
style.MAXScript.6=$(colour.string)
And one more question:
Funtions within my rollout can update and extend the list of objects the rollout is listing. Therefore I would need to make the rollout larger and have new UI elements once the list is updated. For that I need to close the rollout and re-create it. Currently my approach is to only close the rollout and have the user open it again through executing the script one more time. I couldn’t make it work to either update the whole rollout while leaving it open or to close and re-open through code. Any suggestions?
Nope – no can do; I think you’d have to use a .NET windows form for that… these live on the desktop and all other sorts of ‘odd’ behavior, but I think at least you can add controls dynamically
Should be as simple as destroying and re-creating the dialog;
rollout test "test" (
button btn_doit "close and re-open"
on btn_doit pressed do (
destroyDialog test
messagebox "closed"
createDialog test
)
)
createDialog test
If you use a rolloutfloater, the procedure is much the same
Thanks for your answers. Dunno how I could have missed the ‘MAXScript Editor – Customizing…’ chapters in the help docs; I did look for it.
The destroying and re-creating of the dialog is still now working. After destroying the dialog and displaying the messagebox the dialog is re-opened in its old state without the updated listing etc. When I close it manually and re-open it, or when I “destroy” it in the script and open it manually, then it is updated.
you could pass them your UID counter as a parameter… that way you only need 1 function.
I did think about that and tried it for like 5min. But then it seemed to me like a big hassle to first put the right string together and then to execute that in order to have the function access the right UI items. I am not sure though…do you think that way would be more economic than having for each UiID a seperate function (created within the same loop)?
Make sure you evaluate your rollout string -after- destroying the old dialog and -before- creating the new dialog.
It would be much more economic – but it might depend a bit on what you’re doing in that function. But if all you need to keep track of is a counter then having a single function that can handle any of the buttons/controls is definitely preferable.
Here’s some more example code which demonstrates updating the UI (adding a button any time you press the ‘do it’ button), and having a single function that is used for each of the buttons created.
globCounter = 1
fn buttonPress i = (
messagebox ("Button " + i as string + " pressed")
)
fn buildRollout = (
s = stringStream ""
format "rollout test \"test\" (
" to:s
format "button btn_doit \"do it\"
" to:s
for i = 1 to globCounter do (
format "button btn_% \"button %\"
" i i to:s
format "on btn_% pressed do ( buttonPress % )
" i i to:s
)
format "on btn_doit pressed do (
" to:s
format " globCounter += 1
" to:s
format " destroyDialog test
" to:s
format " buildRollout()
" to:s
format " CreateDialog test
" to:s
format ")
" to:s
format ")
" to:s
execute (s as string)
)
buildRollout()
createDialog test