Something I do not quite understand.
Why is Eto chosen as “Recommended” instead using WinForms and/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
That works, thanks @stevebaer.
Still have one issue though. I cannot close the form.
########################
### 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
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')
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.
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.
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()