Python - Eto.Forms.Drawable - Passing Additional Args To Custom Class?

Hello,

I created a CustomButton class with Eto Drawables and am trying to pass 2 arguments to the constructor, a boolean and a color value.

When attempting this I get a TypeError saying that I’m passing 3 arguments and the max number is 2.

It works when I pass the boolean argument by itself, why does the additional color argument cause an issue?

This is my first attempt at passing variables to custom classes with Python and everything else is working well so far.

Beginning of my class code:

class CustomButton(Eto.Forms.Drawable):
    def __init__(self, state, highlight_color):
    
        # Custom Button Control Style Variables
        self.radius = 80
        self.highlight_color_enabled = highlight_color #Eto.Drawing.Colors.BlueViolet (Default Highlight Color)
        self.highlight_color_disabled = Eto.Drawing.Colors.White
        self.border_color = Eto.Drawing.Color(200,200,200)

Code where I create some CustomButton instances:

        # Custom Control Instances
        self.geometry_button = CustomButton(False, Eto.Drawing.Colors.BlueViolet) # Pass Arguments For Per Instance Control Of Button Attributes
        self.query_button = CustomButton(False, Eto.Drawing.Colors.Blue) 

I have more buttons so I want to ensure I am reusing the Class in a smart way by passing variables per instance and not repeating code. Is that the general idea?

Error:

TypeError: CustomButton() takes at most 2 arguments (3 given)

Thank you all for your help!

EDIT:

I found these posts about IronPython2 classes but I still get the same type error even when using the @classmethod version

Here’s my attempt at method:

class CustomButton(Eto.Forms.Drawable):
    @classmethod
    def create(cls, state=False, highlight_color=Eto.Drawing.Colors.BlueViolet):
        instance = cls()
        instance.initialize(state, highlight_color)
        return instance
    
    def initialize(self, state, highlight_color):
        self.state = False
        self.highlight_color = Eto.Drawing.Colors.BlueViolet
    #def __init__(self, state, highlight_color):
    
        # Custom Button Control Style Variables
        self.radius = 80
        self.highlight_color_enabled = highlight_color # Eto.Drawing.Colors.BlueViolet #(Default Highlight Color)
        self.highlight_color_disabled = Eto.Drawing.Colors.White
        self.border_color = Eto.Drawing.Color(200,200,200)
        self.background_color = Eto.Drawing.Colors.Transparent
# Code For The Main Toolbar UI
class MainToolbar(Eto.Forms.Form):

    # Custom Control Instances
    geometry_button = CustomButton(False, Eto.Drawing.Colors.BlueViolet) # Pass Arguments For Per Instance Control Of Button Attributes
    query_button = CustomButton(False, Eto.Drawing.Colors.Blue) 
def EstablishForm():
    form = MainToolbar()
    form.Owner = Rhino.UI.RhinoEtoApp.MainWindow
    form.Show()

if __name__=="__main__":
    EstablishForm()

Hi,

Is it possible that Eto.Forms.Drawable, from which you’re inheriting, has a constructor that only takes a single argument?

You could try something like this:

class Foo:
    def __init__(self, state):
        self.state = state
    
class Bar(Foo):
   def __init__(self, state, color):
       super(Bar, self).__init__(state)
       self.color = color

Since, Eto is a C# library - I think -, I don’t know whether this will work or not.

1 Like

Thanks @diff-arch ,

Unfortunately that didn’t work either.

I believe you are right in that the Eto.Forms.Drawable only takes 1 argument when using IronPython2.

Where as it appears that in C# it works just fine:

    public class CustomButton : Drawable
    {

        public event EventHandler<EventArgs> Clicked;

        public new Color BackgroundColor;
        public Color HighlightColor;
        private Color _backgroundColor;

        private Control _control;

        private bool _isHover = false;

        public CustomButton(Control control)
        {
            _control = control;
            Height = Settings.Instance.General.ButtonHeight;

            HighlightColor = Settings.Instance.Colors.HighlightColor;
        }

There has to be an example somewhere of someone overriding this though.

How else would one pass unique values to the class otherwise?

Am I overlooking something obvious with passing multiple arguments to the Drawable class in IronPython2?

Thank you all for your help!

EDIT:

On the opposite end, going this way I end up with not enough arguments:

class CustomButtonParent(Eto.Forms.Drawable):
    def __init__(self, control):
        self._control = control
    
class CustomButton():
    def __init__(self, control, state, color):
        # super(CustomButton, self).__init__(control) # Call Constructor Of CustomButtonParent
        self._control = control

        self._hover = False
        self._state = state
# Code For The Main Toolbar UI
class MainToolbar(Eto.Forms.Form):

    # CustomButton initialization
    geometry_button = CustomButton(False, Eto.Drawing.Colors.BlueViolet)
    query_button = CustomButton(False, Eto.Drawing.Colors.Blue)
in MainToolbar
TypeError: __init__() takes exactly 4 arguments (3 given)

Eto.Forms.Drawable has three constructors: a default one - taking no arguments -, and two parametrized ones (cf. docs). The one taking a boolean is not a “state” though, but the boolean value informs the class whether it’s intended for a large canvas or not.

I’ve recreated a simplified version of your code and it runs fine:

import System
import Eto

class CustomButton(Eto.Forms.Drawable):
    def __init__(self, large_canvas: bool, state: bool, color: System.Drawing.Color):
        super(CustomButton, self).__init__(large_canvas)
        self.state = state
        self.color = color
    

if __name__ == "__main__":
    btn_color = System.Drawing.Color.Beige
    cb = CustomButton(False, btn_color, True)
    print(cb.state)
    print(cb.color)

You can also call the default constructor if you don’t want to set the largeFormat option:

import System
import Eto

class CustomButton(Eto.Forms.Drawable):
    def __init__(self, state: bool, color: System.Drawing.Color):
        super(CustomButton, self).__init__()
        self.state = state
        self.color = color
    

if __name__ == "__main__":
    btn_color = System.Drawing.Color.Beige
    cb = CustomButton(btn_color, True)
    print(cb.state)
    print(cb.color)

Both self.state and self.color are obviously class properties that are custom to your class.

1 Like

Thank you @diff-arch !

I need to modify this to work for IronPython2 though as it throws a compile error in IPy2.

I can confirm that it is working for Py3 though

EDIT:

Okay I got it working by upgrading my code to use Python3 and adding super after any init:

    def __init__(self):
        super().__init__()

I changed the code a bit to work with lists:

class CustomButton(Eto.Forms.Drawable):
    def __init__(self, state: bool, color: Eto.Drawing.Colors):
        super(CustomButton, self).__init__()

        self._state = state
        self.highlight_color_enabled = color
def EstablishForm():
    form = MainToolbar()
    form.Owner = Rhino.UI.RhinoEtoApp.MainWindow
    form.Show()

# Iterate over the buttons list and create custom button instances with per instance arguments
for i, button in enumerate(MainToolbar.buttons):
    custom_buttons = CustomButton(MainToolbar.b_state[i], MainToolbar.h_color[i])

if __name__ == "__main__":
    EstablishForm()
1 Like

It’s probably the type hints. Simply remove them:

import System
import Eto

class CustomButton(Eto.Forms.Drawable):
    def __init__(self, state, color):
        super(CustomButton, self).__init__()
        self.state = state
        self.color = color
    

if __name__ == "__main__":
    btn_color = System.Drawing.Color.Beige
    cb = CustomButton(btn_color, True)
    print(cb.state)
    print(cb.color)

You’re welcome.

1 Like

I did try that right away but then I get the same argument error:

TypeError: CustomButton() takes at most 2 arguments (3 given)

I was under the impression that Eto did not yet work with Python3 for some reason but obviously that’s not the case so I’m happy to be using Python3 for it and that solved it with your help.

Thanks again, I always appreciate your insight, this was my first attempt at working with class arguments so I was out of my depths. I’m happy to no longer be pulling my hair out and can get to the fun part again.

Cheers!

1 Like