If you want to really kill the form, call it’s .Close() method. If you want to close it now, but you will need it again later, call it’s .Hide() method.
Note that pressing the ‘x’ button of the form will call it’s .Close() method. If you want to prevent your user from disposing the form, you will need to override this behaviour using the FormClosing event.
Thanks, yeah I made an error when referring to the form – it works just as it should now!
As far as the tool goes, it would be nice to essentially build a tool similar to your example and the one we have been talking about on here. One which allows a user to build a character control board within a ui which stores information as needed.
A universal and on the fly editable/buildable UI.
there are two big problems in this method:
#1 without some c# help there is no way to make the selection rectangle semitransparent against other controls
#2 the background will always be flickering badly. And it also can be solved with c# help only
Yeah I noticed #2 – I haven’t gotten around to adding other controls yet (was my next step though) but it seems I need another way than a label – namely that child form without frame you mention. I’m not sure exactly what that is though – but I’ll try to figure it out.
Other than that, it was beginning to look the part:
So when it’s all said and done Denis your recommending that C# be the way to go?
no… there is another way – use a child form without frame as selection rectangle.
i also wrote a system like this a while back. I used 100% dotnet. I used XML serialization to export and build the UI on the fly. I also added a way to get the rig object’s positions from the screen.
Have a look at my write up, it may give you a few ideas!
Hmm, it’s definitely worse than it was – but I’m probably doing something way off. Any comments? Please try to disregard my horrible coding practices, I’m trying to learn as I go along so it’s a bit of a mess.
macroScript laniCharacterStudioDotNet category:"Lani Scripts" buttonText: "Lani Character Studio DotNet"
(
global laniCharStudio_DotnetVisible-- = false
if laniCharStudio_DotnetVisible == undefined then laniCharStudio_DotnetVisible = false
global laniCharacterStudioForm
/*
CREDIT WHERE IT'S DUE:
Most of this was taken from/started out as Paul Neale's excellent tutorial on Dotnet forms in MaxScript
http://paulneale.com/tutorials/dotNet/form/index.htm
Also many thanks to lo on cgsociety
*/
fn NormalizeRectangle hX hY sX sY =
(
local X = amin sX hX
local Y = amin sY hY
local w = abs (hX - sX)
local h = abs (hY - sY)
return (#(x,y,w,h))
)
fn ptWithinRect pX pY rX rY rW rH =
(
local within = false
if ((pX >= rX) AND (pX <= rX+rW)) then (
--within rect X
if ((pY >= rY) AND (pY <= rY+rH)) then (
--within rect Y
within = true
)
)
return within
)
fn formatProps dn=
(
if classOf dn==dotNetObject or classOf dn==dotNetClass then
(
clearListener()
format "Properties:
"
showProperties dn
format "
Methods:
"
showMethods dn
format "
Events:
"
showEvents dn
)else
(
format "% is not a dotNetObject or dotNetClass
" dn
)
)
tColor = ((dotNetClass "system.drawing.color").transparent)
selectionColor = ((dotNetClass "system.drawing.color").fromArgb 102 153 255)
selectionBorder = ((dotNetClass "system.Windows.Forms.BorderStyle").FixedSingle)
charStudioBG = (dotNetclass "System.Drawing.Image").fromfile @"X:\3dsmax\2013\MaxScript\images\characterStudioBackground.png"
--Creates a dotNet form.
form=dotNetObject "system.windows.forms.form"
--You can also use the sort cut for this.
form=dotNetObject "form"
form.isMDIContainer = true
--set the backgroundImage to be equal to the charStudioBG var
form.backgroundImage = charStudioBG
--Create the label that will be the selection square
childform=dotNetObject "form" --"system.windows.forms.label"
--Set the backColor property to the one specified by "selectionColor"
childform.backColor=selectionColor
--Set the panel's borderstyle
--childform.BorderStyle=selectionBorder
--Set the location and size of the label using a rectangle.
childform.Left = 80
childform.Top = 50
childform.Size = (dotNetObject "System.Drawing.Size" 75 95)
--Add the label to the form.
childform.mdiParent = form
--Set the title text.
form.text="Character Studio with Dragging Functionality"
--Set an over all opacity
--Value range is 0-1
form.Opacity=.95
childform.Opacity=.5
borderStyle=(dotNetClass "System.Windows.Forms.FormBorderStyle").None
form.formBorderStyle=borderStyle
form.location=dotNetObject "system.drawing.point" mouse.screenpos[1] mouse.screenpos[2]
form.size=dotNetObject "System.Drawing.Size" 410 512
--FANCY STYLE, TURN OFF FOR DEVELOPMENT
--Set the background color
form.backColor=(dotNetClass "system.drawing.color").black
--Set the transparent color
form.TransparencyKey=(dotNetClass "system.drawing.color").black
borderStyle=(dotNetClass "System.Windows.Forms.FormBorderStyle").None
form.formBorderStyle=borderStyle
childform.formBorderStyle=borderStyle
childform.ShowInTaskbar = false
form.ShowInTaskbar = false
mouseIsDown=false
--hold the starting position of the drag
dragStartX = -1
dragStartY = -1
--Add event handlers for the form.
fn formMouseDown sender arg=
(
--Check to see which mouse button is being pressed.
if arg.button==arg.button.left do (
--LEFT button is down
--formatProps arg;
childform.size = (dotNetObject "System.Drawing.Size" 0 0)
childform.Show()
mouseIsDown=true
dragStartX = arg.x
dragStartY = arg.y
)
if arg.button==arg.button.right do (
--RIGHT button is down
print #right
)
)
fn formMouseUp sender arg=
(
mouseIsDown=false
childform.Hide()
)
fn formMouseMove sender arg=
(
if mouseIsDown do
(
normRect=NormalizeRectangle arg.x arg.y dragStartX dragStartY
childform.Left = normRect[1]
childform.Top = normRect[2]
childform.size=(dotNetObject "System.Drawing.Size" normRect[3] normRect[4])
)
)
--Add the event handlers.
dotNet.addEventHandler form "mouseDown" formMouseDown
dotNet.addEventHandler form "mouseUp" formMouseUp
dotNet.addEventHandler form "mouseMove" formMouseMove
dotNet.addEventHandler childform "mouseDown" formMouseDown
dotNet.addEventHandler childform "mouseUp" formMouseUp
dotNet.addEventHandler childform "mouseMove" formMouseMove
--Set the life time of the control to #dotNet so that it is not garbage collected with the rest of Max script.
dotNet.setLifeTimeControl form #dotNet
--dotNet.setLifeTimeControl childform #dotNet
--Set the parent of the form to be Max.
--Get the max handle pointer.
maxHandlePointer=(Windows.GetMAXHWND())
--Convert the HWND handle of Max to a dotNet system pointer
sysPointer = DotNetObject "System.IntPtr" maxHandlePointer
--Create a dotNet wrapper containing the maxHWND
maxHwnd = DotNetObject "MaxCustomControls.Win32HandleWrapper" sysPointer
--Show the Max form using the wrapper.
if (laniCharStudio_DotnetVisible == false) then (
laniCharStudio_DotnetVisible = true
form.Show(maxHwnd)
laniCharacterStudioForm = form
childform.Show()
) else (
laniCharStudio_DotnetVisible = false
laniCharacterStudioForm.close()
)
--Format all the properties to the listener.
--formatProps form
)
I would not use a label nor a form, I would do it all in the paint method of the one single control. It’s the fastest way and the most controllable way.
what control do you use? the control must be on front of all other controls. i don’t know any way to make it semitransparent without using c#.
I mean not to use a separate control for the selection rectangle, the selection rectangle will just be a graphics.fillRectangle call in the paint event of the canvas control (using a semi-transparent color).
edit: I notice this is just what the OP has done now.
Yes, it appears much more stable than the panel method, and cleaner code too (even if it’s still a bit of a mess).
probably i missed something. as i understood the idea is to have some dialog (form), some panel with controls (buttons, radiobuttons, checkboxes, etc.). using dragging be able to select these controls. for visualization use some rectangle.
you say you are using paint event of the panel. right? but what you draw will be on the back of all other child controls.
how do you draw any semitransparent object over controls?
That’s not how I understand it. See the images in the original post. The OP just wants to be able to select rig control points a-la motionbuilder. For this purpose I don’t see any reason they need to be child controls, they can be ‘virtual’ controls, and handled within the logic of the panel.
do you want to say that the UI is an image only with marked points to click? so is it just a background image only? but this solution is very limited. how to highlight these points for example?
That is not what I mean, I mean the points are not objects that inherit from ‘system.windows.forms.control’, they are essentially defined by rectangles of the canvas control and are drawn inside the paint method of the canvas control. They can be visually represented as anything; rectangles, circles, bitmaps, etc.
that’s definitely not how I handle this thing. I make my all this kind of UI with real controls. It’s much easier for me to handle events, change their visual style…
Don’t get me wrong, in c# the sub-controls would be in their own class with its own events, settings, etc., just one that doesn’t inherit from system.windows.forms.control, and is painted using the graphics object of its parent. I find this gives me a greater degree of control (one example of this is the selection rectangle).
usually i simply don’t have time to design my own controls. all projects are going very fast. i try to use .net controls as much as possible, and add some specific functionality (methods, look, events, etc.) if necessary.
this is how I approached the setup of my system (RigStudio). I used composite controls that built up the overall functionality if I wanted anything more bespoke. I then add custom events to the composite control depending on how I want it handled in max, or just trigger things like selection calls from inside the assembly (via mangedservices).
I haven’t found a way to make it semi-transparent either, other than the panel method I used a while back – but it had the massive flickering problems denisT mentioned.