- Store all child buttons in an array
- set the .Tag property of all buttons (including the control buttons) to the index of their group
- define the event handler function as myFunction sender e = …
- within the function, you can query s.tag to determine which group was activated
- for c in allButtons do c.visible = c.tag == s.tag
I only have a few minutes, otherwise I’d post an example code for you
I would add all your dotNet objects into a struct so you can access them with only one global variable.
Also, no, you cannot send custom parameters to functions via dotNetEventHandlers. You can only access the sender and the event.
Please have a look at the code below:
--Create a form and display it in Max.
--Read about this process in the form & MaxForm tutorial.
global dotNetForm
--Create a struct to access every dotNet object from one global variable
struct dotNetFormStruct (
form=dotNetObject "form", --A comma is required at the end of every function/variable except the very last one.
btn1 = dotNetObject "system.windows.forms.button",
btn2 = dotNetObject "system.windows.forms.button" height:50,
btn3 = dotNetObject "system.windows.forms.button",
btnMS1 = dotNetObject "system.windows.forms.button" ,
btnMS2 = dotNetObject "system.windows.forms.button" ,
btnMS3 = dotNetObject "system.windows.forms.button",
btnMSGroup = #()
)
dotNetForm = dotNetFormStruct()
--Customise the dotNet objects
dotNetForm.btn1.bounds=dotNetObject "System.drawing.rectangle" 10 10 36 36
dotNetForm.btn1.flatStyle=dotNetForm.btn1.flatStyle.flat
dotNetForm.btn1.backColor=dotNetForm.btn1.backColor.darkRed
dotNetForm.btn1.text="1"
dotNetForm.btn2.bounds=dotNetObject "System.drawing.rectangle" 48 10 36 36
dotNetForm.btn2.flatStyle=dotNetForm.btn2.flatStyle.flat
dotNetForm.btn2.backColor=dotNetForm.btn2.backColor.darkGreen
dotNetForm.btn2.text="2"
dotNetForm.btn3.bounds=dotNetObject "System.drawing.rectangle" 86 10 36 36
dotNetForm.btn3.flatStyle=dotNetForm.btn3.flatStyle.flat
dotNetForm.btn3.backColor=dotNetForm.btn3.backColor.darkBlue
dotNetForm.btn3.text="3"
dotNetForm.btnMS1.bounds=dotNetObject "System.drawing.rectangle" 10 48 112 24
dotNetForm.btnMS1.flatStyle=dotNetForm.btn1.flatStyle.flat
dotNetForm.btnMS1.backColor=dotNetForm.btn1.backColor.darkRed
dotNetForm.btnMS1.text="MaxScript1.ms"
dotNetForm.btnMS1.visible = false
dotNetForm.btnMS2.bounds=dotNetObject "System.drawing.rectangle" 10 48 112 24
dotNetForm.btnMS2.flatStyle=dotNetForm.btn1.flatStyle.flat
dotNetForm.btnMS2.backColor=dotNetForm.btn1.backColor.darkGreen
dotNetForm.btnMS2.text="MaxScript2.ms"
dotNetForm.btnMS2.visible = false
dotNetForm.btnMS3.bounds=dotNetObject "System.drawing.rectangle" 10 48 112 24
dotNetForm.btnMS3.flatStyle=dotNetForm.btn1.flatStyle.flat
dotNetForm.btnMS3.backColor=dotNetForm.btn1.backColor.darkBlue
dotNetForm.btnMS3.text="MaxScript3.ms"
dotNetForm.btnMS3.visible = false
sysPointer=dotNetObject "system.intPtr" (windows.getMaxHWND())
maxHandle=dotNetObject "maxCustomControls.win32HandleWrapper" sysPointer
dotNetForm.form.show maxHandle
dotNetForm.form.bounds=dotNetObject "system.drawing.rectangle" 10 90 400 400
dotNetForm.form.text="DotNet UI"
--Functions (These can also be added to the stuct, but if you add them an event handler can not access them directly. Instead you must link to them through a function. See below)
-- function showGroup1Link sender e = dotNetForm.showGroup1 sender e
-- dotNet.addEventHandler showGroup1Link
function ShowGroup1 sender e =
(
print sender --this will give you access to the button that caused the event
print e --this will give you the event with various things you can do, such as cancel the event.
dotNetForm.btnMS1.visible = true
dotNetForm.btnMS2.visible = false
dotNetForm.btnMS3.visible = false
)
function ShowGroup2 sender e=
(
dotNetForm.btnMS1.visible = false
dotNetForm.btnMS2.visible = true
dotNetForm.btnMS3.visible = false
)
function ShowGroup3 sender e =
(
dotNetForm.btnMS1.visible = false
dotNetForm.btnMS2.visible = false
dotNetForm.btnMS3.visible = true
)
--Add the pictureBox to the form
dotNetForm.form.controls.add dotNetForm.btn1
dotNetForm.form.controls.add dotNetForm.btnMS1
dotNetForm.form.controls.add dotNetForm.btn2
dotNetForm.form.controls.add dotNetForm.btnMS2
dotNetForm.form.controls.add dotNetForm.btn3
dotNetForm.form.controls.add dotNetForm.btnMS3
--//Button actions
dotNet.addEventHandler dotNetForm.btn1 "click" ShowGroup1
dotNet.addEventHandler dotNetForm.btn2 "click" ShowGroup2
dotNet.addEventHandler dotNetForm.btn3 "click" ShowGroup3
Hmm odd, when I paste in the code it adds a few spaces between some words. “.flatstyle” has become “.flatstyl e”! Has anyone seen this before?
I’ve attached it below. lol at having to put it in a zip to upload it! You would have thought .ms would be a valid file format
This is how I usually build my dotnet tools. I use a control factory to avoid all that long repetitive code.
Of course all the functions can be customized to your needs.
global exampleDotNetTool
struct exampleDotNetToolStr
(
--components
form,
parentBtns,
childBtns,
--handlers
fn parentClicked s e =
(
for b in exampleDotNetTool.childBtns do b.visible = b.tag == s.tag
),
fn childClicked s e =
(
format "child of group % pressed
" s.tag
),
--initialization functions
fn controlFactory type text backColor X Y W H tag =
(
local ctr = dotNetObject type
ctr.text = text
ctr.bounds = dotNetObject "System.Drawing.Rectangle" X Y W H
ctr.backColor = (dotNetClass "System.Drawing.Color").fromArgb backColor.a backColor.r backColor.g backColor.b
ctr.tag = tag
ctr
),
fn initializeForm =
(
form = dotNetObject "maxCustomControls.maxForm"
form.showInTaskbar = false
form.text = "Dotnet Tool Example"
form.bounds = dotNetObject "System.Drawing.Rectangle" 100 100 200 300
form.controls.addRange parentBtns
form.controls.addRange childBtns
local sysPointer = dotNetObject "System.IntPtr" (windows.getMaxHWND())
local maxHandle = dotNetObject "maxCustomControls.win32HandleWrapper" sysPointer
form.show maxHandle
),
fn initializeControls =
(
local parentBtnDefs = #( \
#("Button", "Parent 1", red, 10, 10, 50, 50, 1),
#("Button", "Parent 2", green, 70, 10, 50, 50, 2),
#("Button", "Parent 3", blue, 130, 10, 50, 50, 3)
)
local childBtnDefs = #( \
#("Button", "Child 1A", red, 10, 70, 50, 50, 1),
#("Button", "Child 1B", red, 70, 70, 50, 50, 1),
#("Button", "Child 2A", green, 10, 130, 50, 50, 2),
#("Button", "Child 2B", green, 70, 130, 50, 50, 2),
#("Button", "Child 3A", blue, 10, 190, 50, 50, 3),
#("Button", "Child 3B", blue, 70, 190, 50, 50, 3)
)
parentBtns = for b in parentBtnDefs collect (controlFactory b[1] b[2] b[3] b[4] b[5] b[6] b[7] b[8])
for b in parentBtns do dotnet.addEventHandler b "Click" parentClicked
childBtns = for b in childBtnDefs collect (controlFactory b[1] b[2] b[3] b[4] b[5] b[6] b[7] b[8])
for b in childBtns do dotnet.addEventHandler b "Click" childClicked
initializeForm()
),
init_trigger = initializeControls() --auto-initialize the controls on struct creation
)
::exampleDotNetTool = exampleDotNetToolStr()
Really nice code optimisation lo! Thanks for sharing, I’ll be sure to have a proper look through it a little later when I have some free time.
It’s definitely a good idea to loop through each button rather than applying settings individually in repetitive code.
Cheers,
Tim that is a good idea. Placing the buttons into the struct and then controlling them.
I noticed the spacing thing happening to me as well.
A way that I got around that was copy and pasting the code into a text document then copying it from there into the cgtalk text field.
It seems like a bummer that you can not send out custom parameters into the functions. The ability to streamline one functions versatility seems to be a bit more limited then in that case. Of course you can always just write more code to achieve the desired effect regardless.
I knew in writing the functions separately for each button was super REDUNDANT and frowned upon, but I had written that way so I would be able to ask the question about sending custom parameters through functions, in return allowing me to condense it all into one function.
Lo great work on the post. I really appreciate you sharing you code here on the thread. As well as Tim. I’m definitely picking up things the more and more this develops. I’ll do another round of revisions and developing this evening and post later today. I’ve got some cool ideas that I want to do with this UI. It also helps a lot to be able to develop this and at the same time having you guys overlooking and helping me make it efficiently written from the start. You’ve definitely condensed the code a ton. I’m going to check it out here and look into a bit more to completely understand it. Thank you for the example you’ve posted here. It will surely help.
It seems like the Tag property in dotNet is a underrated property. It makes me think of the User Defined panel in 3ds max. That is a very useful place for control objects/scenes via maxscript. Rather than storing information on scene/root nodes or tracks. Aside from that the Tag property seems like it is definitely something to become very familiar with and something to get used to using.
Just to understand a bit more on how functions work within the dotNet galaxy I was wondering how would I write one function that would change the color for an object’s wirecolor but by passing a custom variable through the function. Below is an example of what I’ve done using the maxscript + rollout + dotnet to do what I just explained. One function and one custom variable. Just simple example. My question being how would I do the equivalent of this using solely dotNet.
try(destroyDialog rlMattes)catch()
rollout rlMattes "Mattes"
(
dotNetControl btnMatteRed "system.windows.forms.button" height:30 width:30 pos:[5,5]
dotNetControl btnMatteGreen "system.windows.forms.button" height:30 width:30 pos:[40,5]
dotNetControl btnMatteBlue "system.windows.forms.button" height:30 width:30 pos:[75,5]
dotNetControl btnMatteBlack "system.windows.forms.button" height:30 width:30 pos:[110,5]
dotNetControl btnMatteCyan "system.windows.forms.button" height:30 width:30 pos:[5,40]
dotNetControl btnMatteMagenta "system.windows.forms.button" height:30 width:30 pos:[40,40]
dotNetControl btnMatteYellow "system.windows.forms.button" height:30 width:30 pos:[75,40]
dotNetControl btnMatteWhite "system.windows.forms.button" height:30 width:30 pos:[110,40]
dotNetControl btnDelLites "system.windows.forms.button" height:24 width:135 pos:[5,75]
fn fnMatteMat col = (
MatteMaterial = StandardMaterial diffuse:col Selfillumination:100
return MatteMaterial
)
-- Red
on btnMatteRed mouseDown senderArg arg do (for obj in selection do obj.material = fnMatteMat red)
-- Green
on btnMatteGreen mouseDown senderArg arg do (for obj in selection do obj.material = fnMatteMat green)
--Blue
on btnMatteBlue mouseDown senderArg arg do (for obj in selection do obj.material = fnMatteMat blue)
--Black
on btnMatteBlack mouseDown senderArg arg do (for obj in selection do obj.material = fnMatteMat black)
--Cyan
on btnMatteCyan mouseDown senderArg arg do (for obj in selection do obj.material = fnMatteMat (color 0 255 255))
--Magenta
on btnMatteMagenta mouseDown senderArg arg do (for obj in selection do obj.material = fnMatteMat (color 255 0 255))
--Yellow
on btnMatteYellow mouseDown senderArg arg do (for obj in selection do obj.material = fnMatteMat yellow)
--White
on btnMatteWhite mouseDown senderArg arg do (for obj in selection do obj.material = fnMatteMat white)
--Delete Lights
on btnDelLites mouseDown senderArg arg do (delete Lights)
on rlMattes open do
(
dnColor = dotNetClass "System.Drawing.Color"
btnMatteRed.flatStyle=btnMatteRed.flatStyle.flat
btnMatteGreen.flatStyle=btnMatteRed.flatStyle.flat
btnMatteBlue.flatStyle=btnMatteRed.flatStyle.flat
btnMatteBlack.flatStyle=btnMatteRed.flatStyle.flat
btnMatteCyan.flatStyle=btnMatteRed.flatStyle.flat
btnMatteMagenta.flatStyle=btnMatteRed.flatStyle.flat
btnMatteYellow.flatStyle=btnMatteRed.flatStyle.flat
btnMatteWhite.flatStyle=btnMatteRed.flatStyle.flat
btnDelLites.flatStyle = btnDelLites.flatStyle.flat
dnFontStyle = dotNetClass "System.Drawing.FontStyle"
--myFontStyle = dotnet.combineenums dnFontStyle.bold dnFontStyle.italic
btnDelLites.font = dotNetObject "System.Drawing.Font" "Veranda" 8 --myFontStyle
btnDelLites.text="Delete Lights"
btnDelLites.TextAlign= (dotNetClass "System.Drawing.ContentAlignment").MiddleCenter
btnMatteRed.backColor=dnColor.FromArgb 255 0 0
btnMatteRed.flatappearance.bordercolor = dnColor.FromArgb 128 0 0
btnMatteGreen.backColor=dnColor.FromArgb 0 255 0
btnMatteGreen.flatappearance.bordercolor = dnColor.FromArgb 0 128 0
btnMatteBlue.backColor=dnColor.FromArgb 0 0 255
btnMatteBlue.flatappearance.bordercolor = dnColor.FromArgb 0 0 128
btnMatteBlack.backColor=dnColor.FromArgb 0 0 0
btnMatteBlack.flatappearance.bordercolor = dnColor.FromArgb 128 128 128
btnMatteCyan.backColor=dnColor.FromArgb 0 255 255
btnMatteCyan.flatappearance.bordercolor = dnColor.FromArgb 0 128 128
btnMatteMagenta.backColor=dnColor.FromArgb 255 0 255
btnMatteMagenta.flatappearance.bordercolor = dnColor.FromArgb 128 0 128
btnMatteYellow.backColor=dnColor.FromArgb 255 255 0
btnMatteYellow.flatappearance.bordercolor = dnColor.FromArgb 128 128 0
btnMatteWhite.backColor=dnColor.FromArgb 255 255 255
btnMatteWhite.flatappearance.bordercolor = dnColor.FromArgb 128 128 128
)
)
createDialog rlMattes 145 104
You can use the tag property for this too, set the .tag property of the button to the color it should set the object material to, and just use that as the function parameter. (you can even use the .backcolor property in your example, don’t need the .tag property)
btw, the “system.windows.forms” namespace is automatically loaded in maxscript, so you don’t have to write “system.windows.forms.button”, you can just write “button”.
This is maybe a stupid idea but when you are setting your event listeners you could try to put the call of the function in a variable and then give that variable as function when adding the eventlistener
like :
local blabla = somefunction parameter1 parameter2
dotNet.addEventHandler btn1 “click” blabla
I have never tried it …
Assuming that would work, what would that give you?
You’d still have no control over parameter1 and parameter2 based on the calling control, unless you’re querying properties of the sender, which is what you’d do if you were calling the function directly.
So you can essential still run a function with variable using dotNet but using the tag property of the button as the place to hold the variable.
I’ve written a rather simple material color changer. I wanted to us the point3 color to set the color rather that the color of the button. I did it this way just for the sake of trying it that way.
I wanted to do this just as a quick test. It’s not for anything in particular other than good practice. I wanted to make sure I’m understand the functions & variables for buttons.
I’m sure this could probably be condensed a bit and written a bit more efficiently. As i have mentioned before I’m learning dotNet so I’m not aware of all the places to condense code just yet. Any ideas or examples are more than welcome. Thanks
This is the code.
try(form.close())catch()
fn dotnetcolor r g b = (
(dotNetClass "System.Drawing.Color").fromARGB r g b
)
font=dotNetObject "System.Drawing.Font" "Arial" 8
fn fnMatteMat col = (
col = execute col
MatteMaterial = StandardMaterial diffuse:col Selfillumination:100
return MatteMaterial
)
fn colorClicked s e =
(
for obj in selection do obj.material = fnMatteMat s.tag
)
--//Blue button
btnBlue=dotNetObject "button"
btnBlue.flatStyle=btnBlue.flatStyle.flat
btnBlue.backColor=btnBlue.backColor.blue
btnBlue.size=dotNetObject "system.drawing.size" 50 24
btnBlue.location=dotNetObject "system.drawing.point" 10 10
btnBlue.text = "Blue"
btnBlue.foreColor = (dotnetcolor 255 255 255)
btnBlue.font = font
btnBlue.tag = (color 0 0 255) as string
--//Red button
btnRed=dotNetObject "button"
btnRed.flatStyle=btnRed.flatStyle.flat
btnRed.backColor=btnRed.backColor.red
btnRed.size=dotNetObject "system.drawing.size" 50 24
btnRed.location=dotNetObject "system.drawing.point" 60 10
btnRed.text = "Red"
btnRed.foreColor = (dotnetcolor 255 255 255)
btnRed.font = font
btnRed.tag = (color 255 0 0) as string
--//Green button
btnGreen=dotNetObject "button"
btnGreen.flatStyle=btnGreen.flatStyle.flat
btnGreen.backColor=btnGreen.backColor.green
btnGreen.size=dotNetObject "system.drawing.size" 50 24
btnGreen.location=dotNetObject "system.drawing.point" 110 10
btnGreen.text = "Green"
btnGreen.foreColor = (dotnetcolor 255 255 255)
btnGreen.font = font
btnGreen.tag = (color 0 255 0) as string
--//Event Handlers
dotnet.addEventHandler btnBlue "Click" colorClicked
dotnet.addEventHandler btnRed "Click" colorClicked
dotnet.addEventHandler btnGreen "Click" colorClicked
form=dotNetObject "form"
form.controls.add btnBlue
form.controls.add btnRed
form.controls.add btnGreen
form.show()