[python] Why Eto and not WinForms or WPF?

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.

1 Like

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.

1 Like

Can I benefit on learning Eto to write WinForms application later?
What about the cross platform .Net Core that includes Winforms?

.NET core is cross platform, but Winforms is not. Winforms in general is probably the easiest toolkit to learn, but it is also an old toolkit that Microsoft stopped adding functionality to in favor of their WPF toolkit. Then again, Winforms may be enough for what you personally need.

1 Like

I consider to learn GUI programming, however technologies are emerging every year and opportunities are just opening. It is very challenging to pick one for good.

For Rhino I could consider Eto or Winforms. I purchased a book for learning C# recently that dealt with WPF. The book was not that organized, so I put it back. I will take some research how WPF works later.
Winforms also have the option for flat layout. I think the most important is the application as result, but it would be great to find something handy general that easy to learn and use.

I believe it is only fair since McNeel push people to use Eto to develop a “designer” instead of expecting people to code each piece of the gui element by element. I proposed this at least once already.

I hope I’m not mistaken but @piac is (one of) the developer(s) of Eto. Since you have him in your team that should be relatively easy to do. Also SharpDevelop project has open source designer tool for WinForms, perhaps it could be adjusted to detect Eto controls from the DLL. Currently it doesn’t.

Until then, I’ll continue to use WinForms generated by SharpDevelop4

Steve,

I’m getting a little desperate for help with this and I’ve posted on the general Forum and gotten no replies. It seems you helped out Ivelin Peychev with this and I’ve downloaded and run his code with the advice you gave him and it works with his code. Problem is it will not work with mine. I have pasted in a very simple example of a modeless form based on the example: https://github.com/mcneel/rhino-developer-samples/blob/6/rhinopython/SampleEtoModelessForm.py

The code I’ve pasted below will close normally when the X is pushed on the top right corner of the form but crashes Rhino if the close button is pushed. I’ve tried many variations and come up empty.

Any help would be greatly appreciated.

Eric

# 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 controls for the dialog
        self.m_label = forms.Label(Text = 'Enter Your Name:')
        self.m_textbox = forms.TextBox(Text = None)

        # Create the default button
        self.DefaultButton = forms.Button(Text = 'OK')
        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)
        
        #Textbox 1
        layout.AddRow(self.m_label, self.m_textbox)
        layout.AddRow(None) # spacer

        #Buttons
        layout.AddRow(self.DefaultButton, self.AbortButton)

        # Set the dialog content
        self.Content = layout
        print('')
        
    # Start of the class functions

    # Get the value of the textbox(Returns a string)
    def GetText(self):
        return self.m_textbox.Text

       
    # 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")
        self.Close(True) 


    # OK button click handler
    def OnOKButtonClick(self, sender, e):
        print("OK Pushed")



    ## 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

if __name__ == '__main__':
    RequestRoomNumber()

Hi @eric.bunn,

Do you really need a modeless dialog? Or would a modal dialog work?

– Dale

I need to interact with items in the Rhino Window. For example selecting something. I’ve set up a userform using ShowModal and it locks me out of Rhino. The modeless UF allows me to do what I need to do but I have to close the form with the X. Any suggestions would be greatly appreciated.

Eric

@eric.bunn - have you seen this sample?

– Dale

1 Like

Dale,

I am not aware of this example. I downloaded it and this may work for me. I tried it with a GetObject and it worked fine. I’ll experiment with it, thank you so much.

Eric

Dale

Quick question.

The call: Rhino.UI.EtoExtensions.PushPickButton(self, self.OnPickPoint) calls the function OnPickPoint. It appears that the function allows you to run commands involving interaction with Rhino. That’s great. I’m curious though, can the function call a single command without it being wrapped within another function?

Eric

I’m sorry, but I don’t understand the question. Can you clarify what you want to do, or provide some code sample?

– Dale

I believe a lot of confusion is because:

  • Eto is an exotic framework

  • IronPython is an exotic framework

  • GUI creation on a scripting level is exotic

  • Mixing “Model” with “View” Logic is actually very bad practise

  • WPF and so Eto has a steep learning curve

  • Insufficent Code Editor

On the other hand, if you know how to create WPF or Forms Apps (or any other Win GUI Framework), then you will see that the Rhino part is much simpler to master, because the actual API interaction required, is small. But this means, I would start the other way around. Create an GUI within an own app/library and just learn how to invoke this from Rhino or any other Win32 App.( All you need for this is the App window handle, the dispatcher of the actual GUI Thread and some methods to interact with the apps model logic).

1 Like