Eto form: button clicked

Hi
In this example of Mahdiyar
How we can get which button clicked in realtime as output

import Rhino
import Eto.Forms as forms
import Eto.Drawing as drawing
class EtoButtons(forms.Dialog[bool]):
    def __init__(self):
        self.Title = 'EtoButtons'
        self.Padding = drawing.Padding(10)
        self.Resizable = False

        self.FirstButton = forms.Button(Text = 'First')
        self.FirstButton.Click += self.OnButtonClick

        self.SecondButton = forms.Button(Text = 'Second')
        self.SecondButton.Click += self.OnButtonClick

        layout = forms.DynamicLayout()
        layout.Spacing = drawing.Size(5, 5)
        layout.AddRow(self.FirstButton, self.SecondButton)

        self.Content = layout

    def OnButtonClick(self, sender, e):
        print(sender.Text + " is clicked!")

dialog = EtoButtons();
dialog.ShowModal(Rhino.UI.RhinoEtoApp.MainWindow)

Instead of using Text on Button it is better to use Control.Tag Property. That way you have more freedom in what to assign to your controls as data that you may want to use in event handlers. Not all controls have a Text property, but they all do have the Tag property.

3 Likes

Thank you very much @nathanletwory
That maybe solve also another problem

1 Like

An example of how you could use it:

See earlier in the code how the Tag is set for all controls that need it.

1 Like

In that case, it would be nice to add that info here: Rhino - Eto Controls in Python

But I don’t quite understand why that affects event handlers, can you elaborate?

Thank you @nathanletwory
I test it and it work fine , but still i don’t figure out how to compile ghpy component with windows form.
I always have a problem with ghenv.Component.ExpireSolution(True) and can’t get the data from the form.

from System.Drawing import Point
from System.Windows.Forms import*

class HelloWorldForm(Form):
    
    def __init__(self):
        
        start = Button()
        start.Text = "Start"
        start.Location = Point(50, 100)
        start.Click += self.startPressed
        start.Click += self.expire
        
        stop = Button()
        stop.Text = "Stop"
        stop.Location = Point(140, 100)
        stop.Click += self.stopPressed
        stop.Click += self.expire
        
        self.Controls.Add(start)
        self.Controls.Add(stop)
        
    def expire(self,sender,e):
        ghenv.Component.ExpireSolution(True)
        
    def startPressed(self, sender, e):
        self.Tag = 'test','rhino','grasshopper'
        
    def stopPressed(self, sender, e):
        self.Tag = 10,20,25
        
if x:
    if 'form' in globals():
        form.Close()
    form = HelloWorldForm()
    form.Show()

if 'form' in globals():
    a = form.Tag

test form.gh (3.1 KB)

The Tag property is a way to pass any type of data, since Tag gets and sets an object. In the use case that I posted I set an enumeration value. Code-wise this is much more powerful than having just a string that you may have to construct and parse in exotic ways to tag along data. It gives type safety for instance. So the adapted code for @anon39580149 at the end of the reply.

How do you really see this problem manifest? I see always your form.Tag content on a regardless of which of the two buttons I click, or how many times the dialog gets recreated.

I adapted a bit the Python code for your component. Using Tag on the form to communicate data to the component itself is clever, although it wasn’t what I meant initially. So in the updated code you can see how I set a custom class instance to the Tag for each button. Both use the same handler, inside the handler I check the button Tag and use that as well.

from System.Drawing import Point
from System.Windows.Forms import*

class SomeCustomType():
    def __init__(self, nr):
        self.A = nr

class TestForm(Form):
    
    def __init__(self):
        start = Button()
        start.Text = "Start"
        start.Location = Point(50, 100)
        start.Click += self.someButtonPressed
        start.Tag = SomeCustomType(10)
        start.Click += self.expire
        
        stop = Button()
        stop.Text = "Stop"
        stop.Location = Point(140, 100)
        stop.Click += self.someButtonPressed
        stop.Tag = SomeCustomType(20)
        stop.Click += self.expire
        
        self.Controls.Add(start)
        self.Controls.Add(stop)
        self.Tag = "waiting"
        
    def expire(self,sender,e):
        ghenv.Component.ExpireSolution(True)

    def someButtonPressed(self, sender, e):
        form.Tag = repr(sender), repr(sender.Tag)
        if sender.Tag.A == 10:
            form.Tag = 'test', 'rhino', 'grasshopper', str(sender.Tag.A)
        else:
            form.Tag = 10, 20, 25, sender.Tag.A

if x:
    if 'form' in globals():
        form.Close()
    form = TestForm()
    form.Show()

if 'form' in globals():
    a = form.Tag
1 Like

Thank you @nathanletwory
This is very useful, the problem happened when i switch to SDK mode.

Sorry, I do not know what SDK mode is :slight_smile:

Thank you,no problem :slight_smile:
I will try to understand a C# example of @DavidRutten
Maybe it will work with Python

@anon39580149 only now I realize that you are not even using Eto.Forms controls to do your work in, you’re using System.Windows.Forms. After some time of trying things and learning the hard way that type() and isinstance() don’t work in GH Python here is a version that 1) uses Eto.Forms and 2) has multiple custom classes in the Tags of Buttons.

import Eto.Forms as ef
import Eto.Drawing as ed
import Rhino

class SomeCustomType():
    def __init__(self, nr):
        self.A = nr

class OtherCustomType():
    def __init__(self, nr):
        self.B = nr

class TestForm(ef.Form):
    
    def __init__(self):
        start = ef.Button()
        start.Text = "Start"
        start.Click += self.someButtonPressed
        start.Tag = SomeCustomType(1)
        start.Click += self.expire
        
        stop = ef.Button()
        stop.Text = "Stop"
        stop.Click += self.someButtonPressed
        stop.Tag = OtherCustomType(2)
        stop.Click += self.expire
        
        layout = ef.DynamicLayout()
        layout.Spacing = ed.Size(10, 10)
        layout.Padding = ed.Padding(10, 10)
        layout.AddRow(start, stop)
        
        self.Content = layout

        self.Tag = "waiting"
        
    def expire(self,sender,e):
        ghenv.Component.ExpireSolution(True)

    def someButtonPressed(self, sender, e):
        t = str(sender.Tag)
        form.Tag = "SomeCustomType" in t
        if  "SomeCustomType" in t: # does not work: type(sender.Tag) == SomeCustomType, nor does isinstance work: isinstance(sender.Tag, SomeCustomType)
            form.Tag = 'test', 'rhino', 'grasshopper', str(sender.Tag.A)
        else:
            form.Tag = 10, 20, 25, sender.Tag.B
 
print TestForm
    #def stopPressed(self, sender, e):
    #    self.Tag = 10,20,25

if x:
    if 'form' in globals():
        form.Close()
    form = TestForm()
    form.Owner = Rhino.UI.RhinoEtoApp.MainWindow
    form.Topmost = True
    form.Show()

if 'form' in globals():
    a = form.Tag

test form.gh (3.1 KB)

1 Like

Thanks @nathanletwory , i appreciate your help.
Yes my first question is general و and when i get the answer than i try to make it work with windows form.
Right now i create this but something is missing , looks like the connection lost between the form and the component.
Maybe someone have an idea how to fix it

from ghpythonlib.componentbase import executingcomponent as component
import Grasshopper, GhPython
import System
import Rhino
from System.Drawing import Point
from System.Windows.Forms import*

class TestForm(Form):
    def __init__(self):
        self.start = Button()
        self.start.Text = "Start"
        self.start.Location = Point(50, 100)
        
        self.stop = Button()
        self.stop.Text = "Stop"
        self.stop.Location = Point(140, 100)
        
        self.Controls.Add(self.start)
        self.Controls.Add(self.stop)
        
        
class MyComponent(component):
    
    def DisplayForm(self):
        if 'form' in globals():
            form.Close()
        form = TestForm()
        form.start.Click += self.startPressed
        form.start.Click += self.expire
        form.stop.Click += self.stopPressed
        form.stop.Click += self.expire
        form.Text = 'Test'
        form.Show(Grasshopper.Instances.DocumentEditor)
        if 'form' in globals():
            return form.Tag
            
    def expire(self,sender,e):
        self.ExpireSolution(True)
        
    def startPressed(self, sender, e):
        form.Text = 'test' ,'rhino','grasshopper'
        
    def stopPressed(self, sender, e):
        form.Text = 10,20,25
        
    def RunScript(self, x):
        if x:
            a = self.DisplayForm()
            print a
            return a

winform_ghpy.gh (3.7 KB)