[python] Why Eto and not WinForms or WPF?

Something I do not quite understand.

Why is Eto chosen as “Recommended” instead using WinForms and/or WPF?

cross platform…I think, (mac and windows).

Cross platform

Eto is a layer on top of WPF on Windows. Eto is a layer on top of Cocoa on Mac.

What if I don’t care about this?

Where can I find examples of modeless usage of wpf and winforms?

That’s up to you

Through books on WPF and WinForms or Microsoft’s website

Well…there are some Rhino specific stuff that are not written there ;).

This one makes Rhino lock itself.

########################
### TESTING WinForms ###
########################
import System
import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino
import time

tol = sc.doc.ModelAbsoluteTolerance


#import clr

#clr.AddReference("System.Windows.Forms")
#clr.AddReference("System.Drawing")

from System.Windows.Forms import Application, Form, Button
from System.Drawing import Size, Point
from System.Windows.Forms import SplitContainer, FlowLayoutPanel

class IForm(Form):
    def __init__(self):
        self.Text = 'Button'
        self.CenterToScreen()
        self.Size = Size(200, 150)
        
        btn = Button()
        btn.Parent = self
        btn.Text = "Quit"
        btn.Location = Point(50, 50)
        btn.Click += self.OnClick
        btn.MouseEnter += self.OnEnter
        
        
        
    def OnClick(self, sender, args):
        self.Close()
        
    def OnEnter(self, sender, args):
        print "button entered"
    
    
    
    
    def OnFormClosed(self, sender, e):
        # 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')
################################################################################
# Creating a dialog instance and displaying the dialog.
################################################################################

def TestSampleEtoModelessForm():
    # See if the form is already visible
    if sc.sticky.has_key('sample_modeless_form'):
        return
    # Create and show form
    form = IForm()
    
    #form = SampleEtoPushPickButtonDialog()
    #form.Owner = Rhino.UI.RhinoEtoApp.MainWindow
    form.ShowDialog()
    # Add the form to the sticky dictionary so it
    # survives when the main function ends.
    sc.sticky['sample_modeless_form'] = form

if __name__ == "__main__":
    ts = time.time()
    #rs.EnableRedraw(False)
    
    TestSampleEtoModelessForm()
    
    print "Elapsed time is {:.2f}".format(time.time()-ts)

Not really; the only thing Rhino specific is getting the MainWindow from RhinoApp which would typically be the parent window for any of your forms.

form.Owner = Rhino.UI.RhinoEtoApp.MainWindow

How can I make it not use Eto here?

https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.form.show?view=netframework-4.8

RhinoApp.MainWindow() is an IWin32Window

1 Like

That works, thanks @stevebaer.

Still have one issue though. I cannot close the form. :frowning:

########################
### TESTING WinForms ###
########################
import System
import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino
import time

tol = sc.doc.ModelAbsoluteTolerance


#import clr

#clr.AddReference("System.Windows.Forms")
#clr.AddReference("System.Drawing")

from System.Windows.Forms import Application, Form, Button
from System.Drawing import Size, Point
from System.Windows.Forms import SplitContainer, FlowLayoutPanel

class IForm(Form):
    def __init__(self):
        self.Text = 'Button'
        self.CenterToScreen()
        self.Size = Size(200, 150)
        
        btn = Button()
        btn.Parent = self
        btn.Text = "Quit"
        btn.Location = Point(50, 50)
        btn.Click += self.OnClick
        btn.MouseEnter += self.OnEnter
        
        
        
    def OnClick(self, sender, args):
        #self.Close()
        Form.Close(self)
        
    def OnEnter(self, sender, args):
        print "button entered"
    
    
    
    
    def OnFormClosed(self, sender, e):
        # 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')
################################################################################
# Creating a dialog instance and displaying the dialog.
################################################################################

def TestSampleEtoModelessForm():
    # See if the form is already visible
    if sc.sticky.has_key('sample_modeless_form'):
        return
    # Create and show form
    form = IForm()
    
    #form = SampleEtoPushPickButtonDialog()
    #form.Owner = Rhino.UI.RhinoEtoApp.MainWindow
    form.Show(Rhino.RhinoApp.MainWindow())
    # Add the form to the sticky dictionary so it
    # survives when the main function ends.
    sc.sticky['sample_modeless_form'] = form

if __name__ == "__main__":
    ts = time.time()
    #rs.EnableRedraw(False)
    
    TestSampleEtoModelessForm()
    
    print "Elapsed time is {:.2f}".format(time.time()-ts)

Your OnFormClosed is the problem. Delete that function to see the form close

1 Like

I thought that was required so that you don’t open the form twice?

Or is it required only for Eto?

@stevebaer,
is the problem with Eto not being able to create dockable windows with python also valid for WinForms and WPF?

I believe that code will fail under both WinForms and Eto when you are working with non-modal user interface.

Eto is WPF on Windows and yes you will not be able to create dockable UI with python with WinForms or WPF.

The problem is OnFormClosed is a virtual function that takes a single parameter. Just change your code to

    def OnFormClosed(self, e):
        # 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')
1 Like

Soo it was the sender that was the problem.

Thanks @stevebaer, btw my previous code worked with Eto with sender in it. I copy this from one of the Eto examples.