This is going to make all you computer science buffs cringe, but today I learned a really dirty way of managing 3dsMax UI states in a Maxscript rollout or DotNet form. By hooking up a UI refresher to a timer object, you can have your front-end refresh dozens or hundreds of times per second- probably without a performance hit!
Consider the following script:
global hForm, mCheckbox, thisTimer
fn whenCheckboxIsPressed a b =
if MCRUtils.IsCreating Box
then (Max Select; try((hForm.controls.item(0)).checked = false) catch())
else Macros.run 26615
fn updateUI =
hForm.controls.item(0)).checked = MCRUtils.IsCreating Box
--Create a DotNet Checkbox
mCheckbox = dotNetObject "System.Windows.Forms.Checkbox"
mCheckbox.appearance = (dotnetClass "System.Windows.Forms.Appearance").Button
mCheckbox.text = "Box Button"
mCheckbox.location = dotNetObject "System.Drawing.Point" 0 0
--Create a DotNet Form
global hForm = dotNetObject "System.Windows.Forms.Form"
hForm.topmost = true
hForm.controls.add mCheckbox --add the Button to the Form
thisTimer = dotNetObject "System.Windows.Forms.Timer"
thisTimer.interval = 10
--Add an Event Handler for the click event:
dotNet.addEventHandler mCheckbox "click" whenCheckboxIsPressed
dotNet.addEventHandler thisTimer "tick" updateUI
hForm.show() --show the Form with the Checkbox
First, we declare our important Maxscript variables globally so that they can be accessed anywhere. This is a scoping issue; use this technique to taste.
Then we declare the function for when the checkbox is pressed, and accept the sender and event args in a and b respectively. In this function, we dive into the hForm.controls collection and retrieve the control to set it’s “checked” parameter. We set a Try()Catch() block around it because the timer will continue for a short while after the window is closed. Without this expression, you’ll get an error 100 times per second and you’ll have to restart 3dsMax.
The second function is the UI update. In this case, we just set the “checked” parameter equal to a Boolean expression checking to see if the user is engaged in some activity. In this case, we want to know if the user is creating a box. For more of these cases, read the Macroscripts included in 3dsMax and you can derive all sorts of neat “Is the user doing this” type expressions.
The rest is fairly self explanatory. We just create the checkbox, and assign it the visual characteristics we need. We create the DotNet form and assign the checkbox to it, and then create the timer and give it an interval rate of 10 (that is, 1000/10 or 100x per second).
We then link up the two event handlers to functions we declared earlier (button click and update ui), and create the form.
Ta da! The button walks, talks, and acts like a macroscript button, but it’s actually being controlled by DotNet functionality. This means
- More robust visual design for UI items,
- More robust code options and possibly faster performance, and
- When you use my library some day, you’ll be able to get native macroscripts to work alongside your own snazzy code!