Override CreateAttributes for ghpython component

Hi,

I’m trying to create a button on a ghpython component, and I don’t want it as a drop down button. I’ve been trying to override the methods for Render and Layout to create the button according to similar examples in c# online, among others these guides: https://developer.rhino3d.com/guides/grasshopper/custom-attributes/
https://www.grasshopper3d.com/forum/topics/button

However nothing happens to the component. I’ve been trying to create the equivalent code for the ghpython node, but I am not sure if I have understood the c# code correctly. Is it possible to override these methods for a ghpython node to change the appearance of the node? Any help is highly appreciated. The code below is the same as the code in the attached .gh file.

from ghpythonlib.componentbase import executingcomponent as component
import Grasshopper, GhPython
import System
import Rhino
import rhinoscriptsyntax as rs
from System.Windows.Forms import MessageBox
from System.Windows.Forms import MessageBoxButtons

class Attributes_Custom(Grasshopper.Kernel.Attributes.GH_ComponentAttributes): # inherits all methods of GH_ComponentAttributes
    def Layout(self): # override inherited method Layout
        Grasshopper.Kernel.Attributes.GH_ComponentAttributes.Layout() # run layout before changing the definition
        rec0 = Grasshopper.Kernel.GH_Convert.ToRectangle(self.Bounds) #System.Drawing.Rectangle 
        rec0.Height += 22
        rec1 = rec0
        rec1.Y = rec1.Bottom - 22
        rec1.Height = 22
        rec1.Inflate(-2, -2)
        Bounds = rec0
        self.Bounds=Bounds
        ButtonBounds = rec1
        self.ButtonBounds=ButtonBounds
    
    def Render(self,canvas, graphics, channel): # Override Render method
        MessageBox.Show("Render running", "Render", MessageBoxButtons.OK)
        Grasshopper.Kernel.Attributes.GH_ComponentAttributes.Render(canvas, graphics, channel) # run render before changing the definition
        if channel == Grasshopper.GUI.Canvas.GH_CanvasChannel.Objects:
            button = GH_Capsule.CreateTextCapsule(self.ButtonBounds, self.ButtonBounds, Grasshopper.GUI.Canvas.GH_Palette.Black, "Button", 2, 0)
            button.Render(graphics, self.Selected, self.Owner.Locked, False)
            button.Dispose()
    
    def RespondToMouseDown(self,sender,e):
        if e.Button == System.Windows.Forms.MouseButtons.Left:
            rec = self.ButtonBounds
            if rec.Contains(e.CanvasLocation):
                MessageBox.Show("The button was clicked", "Button", MessageBoxButtons.OK)
                return  Grasshopper.GUI.Canvas.GH_ObjectResponse.Handled
        self.sender=sender
        self.e=e
        self.RespondToMouseDown(sender, e)

class MyComponent(component):
    def CreateAttributes(self): # Override inherited method create attributes
        m_attributes=Attributes_Custom(ghenv.Component)
    
    def RunScript(self, x, y):
        a=1
        return a`

custom attributes.gh (4.8 KB)

Hi @amoe

overridden attributes only work in compiled components at the moment. There’s no way to override them in runtime scripting component.

Thanks,

Giulio


Giulio Piacentino
for Robert McNeel & Associates
giulio@mcneel.com

Ok, but should it be possible if I compile the ghPython component like this?

I tried to compile the component, but then the ghenv variable is unknown and there might be some other problems with my code too, but should it be possible if my code is correct?

It would be possible at compile time, yes.
But I really think it would be better done in a programming environment where debugging is available and you have all possibilities and sample, so C# is probably best.

This should have been fixed in an early 6 SR. Please update to the last Service Release of Rhino.

Hi,

I finally had some more time to look at this problem. I agree that it would be easier to do this in Visual studio with C#, but what I want to do is to create a node that easily can be compiled to a node with a button by anyone in my firm who desire, without having to start a visual studio project or asking me for the source code.

I have removed some errors in my code and when I compile the node I get a result close to what I want, but there are still two problems I don’t understand how to solve. This is the node prior and after compilation:

Problem 1: Something is going wrong when I am rendering since the component becomes transparent.

Problem 2: The button does not respond to my button clicks. It is also impossible to move the component with a mouse drag. It only moves when I select multiple objects and move the object next to this node.

This is what my code looks like at this point:

#python
from ghpythonlib.componentbase import executingcomponent as component
import Grasshopper, GhPython
import System
import Rhino
import rhinoscriptsyntax as rs
from System.Windows.Forms import MessageBox
from System.Windows.Forms import MessageBoxButtons

class Attributes_Custom(Grasshopper.Kernel.Attributes.GH_ComponentAttributes): # inherits all methods of GH_ComponentAttributes
    def Layout(self): # override inherited method Layout
        Grasshopper.Kernel.Attributes.GH_ComponentAttributes.Layout(self) # run render before changing the definition
        rec0 = Grasshopper.Kernel.GH_Convert.ToRectangle(self.Bounds) #System.Drawing.Rectangle 
        rec0.Height += 22
        rec1 = rec0
        rec1.Y = rec1.Bottom - 22
        rec1.Height = 22
        rec1.Inflate(-2, -2)
        Bounds = rec0
        self.Bounds=Bounds
        ButtonBounds = rec1
        self.ButtonBounds=ButtonBounds
    
    def Render(self,canvas, graphics, channel): # Override Render method
        Grasshopper.Kernel.Attributes.GH_ComponentAttributes.Render(self, canvas, graphics, channel) # run render before changing the definition
        if channel == Grasshopper.GUI.Canvas.GH_CanvasChannel.Objects:
            button = Grasshopper.GUI.Canvas.GH_Capsule.CreateTextCapsule(self.ButtonBounds, self.ButtonBounds, Grasshopper.GUI.Canvas.GH_Palette.Black, "Button", 2, 0)
            button.Render(graphics, self.Selected, self.Owner.Locked, False)
            button.Dispose()
    
    def RespondToMouseDown(self,sender,e):
        if e.Button == System.Windows.Forms.MouseButtons.Left:
            rec = self.ButtonBounds
            if rec.Contains(e.CanvasLocation):
                MessageBox.Show("The button was clicked", "Button", MessageBoxButtons.OK)
                return  Grasshopper.GUI.Canvas.GH_ObjectResponse.Handled
        self.sender=sender
        self.e=e
        self.RespondToMouseDown(sender, e)

class MyComponent(component):
    def CreateAttributes(self): # Override inherited method create attributes
        self.m_attributes=Attributes_Custom(self) 
    
    def RunScript(self, x, y):
        a=1
        return a

Any help is highly appreciated.

Best regards
Audun Mathias Øvstebø