How to know if Eto forms is closed?

I’m looking to get a boolean result through the output, if the dialog is open or closed, any ideas how to define this?
Here’s a sample code

import Eto.Drawing as drawing
import Eto.Forms as forms

class MyDialog(forms.Dialog):
    def __init__(self):
        self.Title = "Test"
        self.Padding = drawing.Padding(10)

        panel = forms.Panel()
        panel.BackgroundColor = drawing.Colors.AliceBlue
        panel.Content = forms.Label(Text = 'This is a test')

        layout = forms.DynamicLayout()
        layout.AddRow(panel)

        self.Content = layout

def TestMyDialog():
    dialog = MyDialog()
    dialog.ShowModal()

if __name__ == '__main__':
    TestMyDialog()

Hi @mats_magnunson,

there are a bunch of events you can subscribe to with a modal dialog. Note that a modal dialog blocks Rhino, so you can only get something back in your calling function if the dialog has been closed. I’ve added 2 buttons to receive a return value…

ETO_DialogEvents.py (1.7 KB)

_
c.

1 Like

Hi @clement ,
Thanks for providing this nice example, much appreciated. It makes sense, there are way more events related to closing dialogs that I may need.
I realized when using these events on a modeless form, it doesn’t have the same behaviour, maybe because, as you mentioned, your file its a modal dialog.
I’ve tryed to print the “Event: Closed” as your example but it doesnt output anything, even if the closed event is created, it seems it wont return any value. Do your know if there is any different configuration for modeless forms?
Here’s my atempt to print the closed event:

import System
import Rhino.UI
import Eto.Drawing as drawing
import Eto.Forms as forms
import Eto
import scriptcontext as sc

class OptionsPanel(forms.Form):

   def __init__(self):

       self.m_slider = forms.Slider()
       self.m_slider.TickFrequency = 10
       self.m_slider.MinValue = 1
       self.m_slider.MaxValue = 100
       self.m_slider.Value = x
       self.m_slider.ValueChanged += self.OnSliderValueChanged
       self.m_numeric_updown = forms.NumericUpDown()
       self.m_numeric_updown.DecimalPlaces = 0
       self.m_numeric_updown.Increment = 1
       self.m_numeric_updown.MaxValue = 100.0
       self.m_numeric_updown.MinValue = 1.0
       self.m_numeric_updown.Value = x
       self.m_numeric_updown.ValueChanged += self.OnNumericChanged
       self.o_slider = forms.Slider()
       self.o_slider.TickFrequency = 10
       self.o_slider.MinValue = 1
       self.o_slider.MaxValue = 60
       self.o_slider.Value = y
       self.o_slider.ValueChanged += self.OnSliderValueChanged
       self.o_numeric_updown = forms.NumericUpDown()
       self.o_numeric_updown.DecimalPlaces = 0
       self.o_numeric_updown.Increment = 1
       self.o_numeric_updown.MaxValue = 60
       self.o_numeric_updown.MinValue = 1.0
       self.o_numeric_updown.Value = y
       self.o_numeric_updown.ValueChanged += self.OnNumericChanged

       self.o_numeric_updown.ValueBinding.Bind(self.o_slider, "Value", Eto.Forms.DualBindingMode.TwoWay)
       self.m_numeric_updown.ValueBinding.Bind(self.m_slider, "Value", Eto.Forms.DualBindingMode.TwoWay)

       self.DefaultButton = forms.Button(Text="OK")
       self.DefaultButton.Click += self.OnOkButtonClick
       self.AbortButton = forms.Button(Text="Cancel")
       self.AbortButton.Click += self.OnCancelButtonClick

       self.Initialize()
       self.CreateFormControls()

   def Initialize(self):
       self.Padding = drawing.Padding(10)
       self.Resizable = False
       self.Topmost = True
       self.Closed += self.OnFormClosed

   def CreateFormControls(self):
       layout = forms.DynamicLayout()
       layout.Spacing = drawing.Size(5, 5)
       layout.AddRow(None)
       layout.AddRow(self.m_slider, self.m_numeric_updown)
       layout.AddRow(None)
       layout.AddRow(self.o_slider, self.o_numeric_updown)
       layout.AddRow(None)
       layout.AddRow(self.DefaultButton, self.AbortButton)
       self.Content = layout

   def OnSliderValueChanged(self, sender, e):
       ghenv.Component.ExpireSolution(True)

   def OnNumericChanged(self, sender, e):
       ghenv.Component.ExpireSolution(True)

   def GetNumber1(self):
       return self.m_numeric_updown.Value

   def GetNumber2(self):
       return self.o_slider.Value
       
   def OnOkButtonClick(self, sender, e):
       self.Close()
    
   def OnCancelButtonClick(self, sender, e):
       self.Close()

   def OnFormClosed(self, sender, e):
       print "Event: Closed"
       if sc.sticky.has_key('form'):
           form = sc.sticky['form']
           if form:
               form.Dispose()
               form = None
           sc.sticky.Remove('form')

def Dostuff():
   if sc.sticky.has_key('form'):
       return
   form = OptionsPanel();
   form.Show()
   sc.sticky['form'] = form

if z == True:
   Dostuff()

if sc.sticky.has_key('form'):
   form = sc.sticky['form']
   value1 = form.GetNumber1()
   value2 = form.GetNumber2()
else:
   value1 = x
   value2 = y

a = value1
b = value2

H Mats,

modeless forms return immediately once shown and have no return value. So once you run this:

form = OptionsPanel();
form.Show()
....other code here

the code below will continue to run. I am not able to run your example using _EditPythonScript due to some missing variables (x,y,z). If i remove the lines where these variables are used, the form opens. Once i click OK, i see the “Event: Closed” gets printed. Btw. one tip to prevent crashes: put your delegate function codes into try: ... except: blocks. I got one crash though while running your code a second time, i guess it is because you’re trying to Dispose() the modeless form.

_
c.

1 Like

Hi Clement,
Thank you for the tips, maybe there is a diference when runing the script from GhPython compared to run it from _EditPythonScript command. I managed to print the “Event: Closed” on _EditPythinScript as you mentioned, but it doesnt print on GhPython. I mean, it does print the Close Event = False, but after closing, it doesn’t print the Close Event=True.
I’m now trying a different approach by returning the Event value to later put it on a variable, however, it doesnt accept Value as a valid argument, please see bellow

def OnFormClosed(self, sender, e):
      return self.OnFormClosed.Value

Do you know which argument do I need to invoke to return a true/false result?

Hi @mats_magnunson,

Consider declaring your dialog like this:

class MyDialog(Eto.Forms.Dialog[bool]):

Then you can close the dialog like this:

def DefaultButtonClick(self, sender, e):
    self.Close(True)
    
def AbortButtonClick(self, sender, e):
    self.Close(False)

test_string_box.py (3.0 KB)

– Dale

1 Like

Hi @dale ,
Thank you for sharing this example code as well as all the other eto samples which are quite useful.
However it doesnt seem to work with modeless forms

import Eto.Forms as forms
class OptionsPanel(forms.Form[bool]):

I get a runtime error
Snag_5b1ca36

Do you have any other recommended approach on how to know if modeless form is open or closed?

Hi @mats_magnunson,

Store the form in the sticky dictionary.

test_modeless_form.py (2.0 KB)

– Dale

Hi @dale ,
Thanks for the follow-up!
I believe the issue I’m facing is caused by using it on GhPython.
We can see it’s printing well on Rhino _EditPythonScrip

By other hand, it doesn’t output anything whithin GHpython
Animation

I’m using these forms to run GH definitions, this is the main reason why it’s important to get the closed value in order to continue other steps ahead on each definition.
Either by printing it or defining boolean variable a, I don’t mind to explore any possibility available but I just got stuck in this last step and not sure what else to try.
May you please recommend another aproach?

You’ll need to repost this in the Grasshopper category - sorry.

– Dale

Hi @mats_magnunson

Same happen to me, did you find any solution yet?

Thank you.