DrawForeground - Python2 -> Python3

Hello,

I’m attempting to update some of my IronPython components to the new script component and Python 3 language and I’m stuck on the event handlers and I don’t understand what it’s expecting in terms of arguments.

I found this template code related to DrawWires:

"""Grasshopper Script Instance (With Draw Methods)"""
import System
import Rhino
import Grasshopper

import rhinoscriptsyntax as rs

class MyComponent(Grasshopper.Kernel.GH_ScriptInstance):
    def RunScript(self, x, y):
        return x + y

    @property
    def ClippingBox(self):
        return Rhino.Geometry.BoundingBox.Empty

    def DrawViewportWires(self, args):
      pass

    def DrawViewportMeshes(self, args):
      pass

Here’s my working IronPython code:

from ghpythonlib.componentbase import executingcomponent as component

import System
import Rhino as rh
import Rhino.Geometry as rg

class MyComponent(component):
    
    def RunScript(self, P, F, S, D, V):

        if S == None: S = 20
        if D == None: D = True
        if V == None: V = False
        
        self.F = F
        self.P = P
        self.D = D  # Store the value of D as an instance variable
        
        if self.F:
            bitmap = System.Drawing.Bitmap.FromFile(F)
            self.B = rh.Display.DisplayBitmap(bitmap)

        self.S = S
        self.size = V
        
        if self.P and len(P) > 0:
            bb = rg.BoundingBox(P)
            self.bb = bb
        else:
            self.bb = rh.Geometry.BoundingBox.Empty

    def DrawForeground(self,sender, arg):
        if self.D:  # If D is True, draw the sprite in the foreground
            if self.P and self.F:
                items = rh.Display.DisplayBitmapDrawList()
                items.SetPoints(self.P)
                arg.Display.DrawSprites(self.B, items, self.S, self.size)

    def DrawViewportWires(self, arg):
        if not self.D:  # If D is False, draw the sprite as before using DrawViewportWires
            if self.P and self.F:
                items = rh.Display.DisplayBitmapDrawList()
                items.SetPoints(self.P)
                arg.Display.DrawSprites(self.B, items, self.S, self.size)
    
    def get_ClippingBox(self):
        return self.bb
    
    def IsPreviewCapable(self):
        return True

    def __exit__(self):
        rh.Display.DisplayPipeline.DrawForeground -= self.DrawForeground

    def __enter__(self):
        rh.Display.DisplayPipeline.DrawForeground += self.DrawForeground

And my attempt at updating to Python 3:

#from ghpythonlib.componentbase import executingcomponent as component

import System
import Rhino as rh
import Rhino.Geometry as rg

class MyComponent(Grasshopper.Kernel.GH_ScriptInstance):
    
    def RunScript(self, P, F, S, D, V):

        if S == None: S = 20
        if D == None: D = True
        if V == None: V = False
        
        self.F = F
        self.P = P
        self.D = D  # Store the value of D as an instance variable
        
        if self.F:
            bitmap = System.Drawing.Bitmap.FromFile(F)
            self.B = rh.Display.DisplayBitmap(bitmap)

        self.S = S
        self.size = V
        
        if self.P and len(P) > 0:
            bb = rg.BoundingBox(P)
            self.bb = bb
        else:
            self.bb = rh.Geometry.BoundingBox.Empty

    @property
    def DrawForeground(self, sender, args):
        if self.D:  # If D is True, draw the sprite in the foreground
            if self.P and self.F:
                items = rh.Display.DisplayBitmapDrawList()
                items.SetPoints(self.P)
                args.Display.DrawSprites(self.B, items, self.S, self.size)
                pass

    def DrawViewportWires(self, args):
        if not self.D:  # If D is False, draw the sprite as before using DrawViewportWires
            if self.P and self.F:
                items = rh.Display.DisplayBitmapDrawList()
                items.SetPoints(self.P)
                args.Display.DrawSprites(self.B, items, self.S, self.size)
                pass
    
    def get_ClippingBox(self):
        return self.bb
    
    def IsPreviewCapable(self):
        return True

    def __exit__(self):
        rh.Display.DisplayPipeline.DrawForeground -= self.DrawForeground

    def __enter__(self):
        rh.Display.DisplayPipeline.DrawForeground += self.DrawForeground

The error I can’t solve:

1. Error running script: DrawForeground() missing 2 required positional arguments: 'sender' and 'args'

Thank you for your help!

Looking into this right now. Any GH files you can potentially share? I’m getting a weird compile error that I’m looking into as well.

1 Like

Hi @eirannejad ,

Here’s a test file, thanks for looking into it!

I also got a generic compile error and couldn’t manage to see an actual error code or any more information to debug.

custom_symbol_display_test.gh (92.4 KB)

Expected Result (DrawForeground Set True):

Expected Result (DrawForeground Set False):

1 Like

I’m finding a couple of nasty bugs related to this. I recently added the support for ScriptInstance to python so this hasn’t been tested. Thanks for reporting and testing these. I’ll make some fixes and they should be available on next build

2 Likes

Much appreciated, thank you!

@michaelvollrath I got this working and will be available in tomorrow’s build. It might be still buggy as there is a lot happening behind the scenes.

It will be available in tomorrows BETA build for testing

2 Likes

Awesome, thank you @eirannejad ! Looking forward to testing

1 Like

Hi @eirannejad , would you mind sharing the file/code you used in the video you posted?

I tried on my end but still was getting a generic undefined compile error with the new update.

Thank you!

1 Like

Try this please:

test_viewportimage.ghx (200.1 KB)

3 Likes

Beautiful, works great, thank you so much!!

1 Like