How would one add a close button to the modeless userform in the link below? This example closes with the X on top. I would like a button to close the form and do the same cleanup that OnFormClosed does when you hit the X.
unless i missed something in your question, this should be fairly short
import Eto.Forms as forms
class Sample(forms.Form):
# assuming you already have a button control added
button.Click += self.OnButtonClick
def OnButtonClick(self, s, e):
self.Close()
My problem was adding this to a user form, based on the modeless example, would crash Rhino immediately. I have since found showsemimodal which seems to work but I am cautiously experimenting with it to make sure it wonât cause other issues. I want to be able to instigate a Rhino command from the UF and allow the operator to select something on screen.
Iâve pasted in the modified modeless form code below with a close button on it that has the exact same code in it as the function called âOnFormClosedâ. If you close the form with the X the form closes normally with no problems. If you close the form with the Close button Rhino crashes. Iâve added self.close() as well and it crashes. Can someone tell me how to correct this so I can use the close button on the form to close the userform.
Imports
import Rhino
import scriptcontext as sc
import System
import Rhino.UI
import Eto.Drawing as drawing
import Eto.Forms as forms
SampleEtoRoomNumber dialog class
class SampleEtoRoomNumberDialog(forms.Form):
# Dialog box Class initializer
def __init__(self):
# Initialize dialog box
self.Title = 'Identify Assembly Components'
self.Padding = drawing.Padding(10)
self.Resizable = False
#FormClosed event handler
self.Closed += self.OnFormClosed
# Create the default button
self.DefaultButton = forms.Button(Text = 'Create Layout')
self.DefaultButton.Click += self.OnOKButtonClick
# Create the abort button
self.AbortButton = forms.Button(Text = 'Cancel')
self.AbortButton.Click += self.OnCloseButtonClick
# Create a table layout and add all the controls
layout = forms.DynamicLayout()
#Sets spacing between controls(pixels)
layout.Spacing = drawing.Size(5, 5)
#Buttons
layout.AddRow(self.DefaultButton, self.AbortButton)
# Set the dialog content
self.Content = layout
print('')
# Form Closed event handler
def OnFormClosed(self, sender, e):
print("the form has closed")
# Dispose of the form and remove it from the sticky dictionary
if sc.sticky.has_key('sample_modeless_form'):
form = sc.sticky['sample_modeless_form']
if form:
form.Dispose()
form = None
sc.sticky.Remove('sample_modeless_form')
# Close button click handler
def OnCloseButtonClick(self, sender, e):
print("the form has closed")
# Dispose of the form and remove it from the sticky dictionary
if sc.sticky.has_key('sample_modeless_form'):
form = sc.sticky['sample_modeless_form']
if form:
form.Dispose()
form = None
sc.sticky.Remove('sample_modeless_form')
# OK button click handler
def OnOKButtonClick(self, sender, e):
print("This button is OK")
## End of Dialog Class ##
def RequestRoomNumber():
# See if the form is already visible
if sc.sticky.has_key('sample_modeless_form'):
return
# Create and show form
form = SampleEtoRoomNumberDialog()
form.Owner = Rhino.UI.RhinoEtoApp.MainWindow
form.Show()
# Add the form to the sticky dictionary so it
# survives when the main function ends.
sc.sticky['sample_modeless_form'] = form
@Trav sorry if Iâm calling on the wrong person but youâve helped with a few of my Eto questions so i thought you might know
Iâm experiencing similar crashes. Here is a shorter example that reproduced the problem on my machine. I ran this in the rhino python editor.
import Eto.Forms as forms
import Eto.Drawing as drg
import Rhino.Input as rhi
import Rhino.Commands as rhcmd
import Rhino as rh
class MyForm(forms.Form):
def __init__(self):
self.Size = drg.Size(500,200)
self.panel = forms.StackLayout(Orientation = forms.Orientation.Vertical)
self.bttn = forms.Button(Text='pick')
self.bttn.Click += self.OnClick
self.label = forms.Label()
self.panel.Items.Add(self.bttn)
self.panel.Items.Add(self.label)
self.Content = self.panel
def OnClick(self, s, e):
self.Hide()
r, oref = rhi.RhinoGet.GetOneObject(
'pick something',
True,
rh.DocObjects.ObjectType.AnyObject)
if r == rhcmd.Result.Success:
self.label.Text = oref.ObjectId
self.Show()
myform = MyForm()
myform.Owner = rh.UI.RhinoEtoApp.MainWindow
myform.Show()
I got a tip from Dale that allowed me to select items on screen using a modal form. Didnât solve the crashing problem with modeless form but for my purposes it will work for me.
Hiding the dialog doesnât mean its no longer modal. You would need to close the dialog to achieve that. PushPickButton is designed to perform this duty for you.
I thought the hiding of the userform was a nice bonus. The modeless version was always in your face and I found myself having to move it around when I was wanting to select something on screen. It was a good find for sure.
Found my problem. Cross fire between winforms and eto forms in my brain. The crash was because Eto.Forms.Form doesnât have a Hide() method, as I have written in my snippet.
So OP, you can use a modeless Eto.Forms.Form and programmatically âhideâ it when you need. Something like this should work
import Eto.Forms as forms
import Eto.Drawing as drg
import Rhino.Input as rhi
import Rhino.Commands as rhcmd
import Rhino as rh
class MyForm(forms.Form):
def __init__(self):
self.Size = drg.Size(500,200)
self.panel = forms.StackLayout(Orientation = forms.Orientation.Vertical)
self.bttn = forms.Button(Text='pick')
self.bttn.Click += self.OnSelectClick
self.label = forms.Label()
self.panel.Items.Add(self.bttn)
self.panel.Items.Add(self.label)
self.Content = self.panel
def OnSelectClick(self, s, e):
self.Minimize()
try:
r, oref = rhi.RhinoGet.GetOneObject(
'pick something',
True,
rh.DocObjects.ObjectType.AnyObject)
if r == rhcmd.Result.Success:
self.label.Text = oref.ObjectId
except Exception as e: self.label.Text = str(e)
self.BringToFront()
myform = MyForm()
myform.Owner = rh.UI.RhinoEtoApp.MainWindow
myform.Show()
Thanks Travis! When I do use Dialog it will come in handy. I was trying to get at Form so rhino UI thread doesnât lock up behind it other than a pick call.
I tried out your code and it works well. Works more like a Windows Form with the Show and HIde. (I come from a Solidworks/VBA background) If I ever need full control of Rhino while the form is running I could use this.
One problem though. I picked up on this with other modeless forms I tried out.:
I canât pass in variables to the Class. My only work around for this was declaring global variables in the Class and assign a class variable to the global variable. Then I could load them from outside the Class. Kind of a pain. See code below that crashes:
import Eto.Forms as forms
import Eto.Drawing as drg
import Rhino.Input as rhi
import Rhino.Commands as rhcmd
import Rhino as rh
class MyForm(forms.Form):
def __init__(self, testVar):
self._testVar = testVar
self.Size = drg.Size(500,200)
self.panel = forms.StackLayout(Orientation = forms.Orientation.Vertical)
self.bttn = forms.Button(Text='pick')
self.bttn.Click += self.OnSelectClick
self.label = forms.Label()
self.panel.Items.Add(self.bttn)
self.panel.Items.Add(self.label)
self.Content = self.panel
def OnSelectClick(self, s, e):
self.Minimize()
try:
r, oref = rhi.RhinoGet.GetOneObject(
'pick something',
True,
rh.DocObjects.ObjectType.AnyObject)
if r == rhcmd.Result.Success:
self.label.Text = oref.ObjectId
except Exception as e: self.label.Text = str(e)
self.BringToFront()
testVar = "Some Value"
myform = MyForm(testVar)
myform.Owner = rh.UI.RhinoEtoApp.MainWindow
myform.Show()
Hereâs the error:
Message: expected IHandler, got str
Traceback:
line 35, in , âC:\Users\bunner\OneDrive - Sealed Air Corporation\Computer\Desktop\Rhino Scripts\Python Routines\Example Code\Userforms\ETO\Rhino ETO Example Modeless with HideShow.pyâ
this is a bit beyond me but it seems you canât override the constructor
when you instantiate, the constructor with one argument is still called from super
Iâd assign class variables with a class method