If you’re used to scripting your GUIs in Max with the standard rollouts via “createDialog …”, you might be a little confused and lost when you first try to use a 100% .NET Form object instead.
Whatever your reason might be for using .NET Forms instead of standard dialogs, you’ll still want to:
- Create the main form and define its properties
- Define other UI controls, such as buttons, checkboxes etc…
- Define event handlers for specific control objects
- Initialize and display the entire Form with all the controls and functionality tied in
All this is done a little differently in the .NET realm than what you’re used to in MAXScript. But before you start, check out Paul Neale’s great .NET tutorials on his site. Paul provides some great info for anyone trying to use .NET controls in their scripts.
Now, there is one thing I bumped into, you can actually use .NET objects in MAXScript rollouts, however, you cannot use regular max controls in .NET Forms! So, trying to assign a standard button to a .NET Form will result in an error.
You might think that this creates a burden on the TD to actually skin and customize the .NET controls to look like native 3ds Max GUI elements. You can do this, of course, but it’d really be a lot of additional work to hassle around with color classes, HWNDs etc… you actually don’t need to worry about this as there is an Assembly available in standard Max installations. It’s a little .dll, found in the root of Max, called MaxCustomControls.dll. This Assembly contains some of the more exotic controls, such as SceneExplorer, but it also contains a complete Form control that has already been modified so it reflects your 3ds Max environment, including all the colors, themes and even an initialization method for showing the control as a part of the max process/window.
Anyways, back to the topic. You can easily instantiate the MaxForm control as follows:
maxForm = dotNetObject "MaxCustomControls.MaxForm"
This way you have the System.Windows.Forms Form fully tailored to 3ds Max, without any additional work. Standard methods and properties of the .NET Form control are supported, of course. So, all you need now is to start adding controls to it. This is done differently than what you’re used to in rollouts. By simply instantiating buttons, checkboxes, or whatever, inside the scope of the script (because there is no rollout scope) isn’t enough, obviously. For this, there is a Controls property, inherited from the Control.ControlCollection class, that has a few useful methods. The one you’ll need to add controls to the parent object is, naturally, .Add()
Here’s a simple example of declaring a .NET Button and adding it to the MaxForm object:
myButton = dotNetObject "System.Windows.Forms.Button"
Easy stuff! Especially if you’re used to C# or even IronPython. The little confusing part comes when you want to actually assign event handlers to your controls. This is done completely differently from regular rollout event handlers, but it’s also different from C# or IPy. Normally in C# or IPy what you do is assign a method to a event property on individual controls:
myButton.Click += doSomething
This doesn’t work in MAXScript, however, so you have to opt for a specifically tailored solution to this issue, which is the dotNet.addEventHandler method. It accepts three arguments: the object to which you’re adding the eventHandler, the name of the event it should respond to and finally the method you’ll want the object to call when the given event occurs. So, the same example as above in MAXScript looks like this:
dotNet.addEventHandler myButton "Click" doSomething
The doSomething function has to accept two arguments, the sender and the argument list used inside the function to properly identify what object is calling it and what arguments you used (i.e. right click etc…)
Now, finally, you have pretty much everything you need to start building rich .NET GUIs for your scripts. The last thing to do now is to call the Form object with all its controls, methods, handlers etc… and show it. By default, a Form object has a regular Show() method to display the Form, but, this will result in showing an independent window that “falls behind” 3ds Max when you click anywhere in Max. This isn’t desirable for UI controls. Luckily, as I mentioned earlier, the MaxForm object has a special ShowModeless() method that will display the Form and tie it to the 3ds Max handle (HWND). Here’s the last piece of the puzzle. Please note that I’ve also added the dotNet.setLifeTimeControl method to show you that it’s generally a good idea to let the .NET garbage collector take care of the .NET objects, instead of the Max’s one.
dotNet.setLifeTimeControl maxForm #dotNet
That’s it for now. Happy scripting with .NET!