Creating Class for Buttons Returns None



  • Hi,

    Usually, I create buttons by just adding the vanilla lines. I wanted to create a class for buttons but it returns None and gives and me an error of

    line 34, in create
            bmp_btn.SetImage(bmp_color, True)
        AttributeError: 'NoneType' object has no attribute 'SetImage'
    

    Interestingly. The same code works on a vanilla code. So I was thinking there is an additional procedure when creating a class?

    You can check the working code here:

    import c4d
    from c4d import bitmaps, documents, gui, plugins, threading, utils
    
    PLUGIN_ID   = 18113289
    
    class ColorButton(c4d.gui.GeDialog):
    
        def __init__(self):
            self.width = None
            self.height = None
            self.color = None
            self.color = None
            self.btn_id = 3000
    
    
        def create(self, w, h, color,btn_id):
    
            self.width = w
            self.height = h
            self.color = color
    
            bmp_color = c4d.bitmaps.BaseBitmap()
            bmp_color.Init(w, h)
    
            for y in xrange(w):
                for x in xrange(h):
                    bmp_color.SetPixel(x, y, color[0], color[1], color[2])
    
            bcBitmapButton = c4d.BaseContainer()
            bcBitmapButton[c4d.BITMAPBUTTON_BUTTON] = True
    
            bmp_btn = self.AddCustomGui(btn_id, c4d.CUSTOMGUI_BITMAPBUTTON, "", c4d.BFH_CENTER|c4d.BFV_CENTER, w, h, bcBitmapButton)
    
            bmp_btn.SetImage(bmp_color, True)
    
    class MyDialog(c4d.gui.GeDialog):
    
        buttonId = 2000
    
        def CreateLayout(self):
    
            self.SetTitle('Class Button')
    
            # Creating a red button through vanilla lines 
            w = 50
            h = 50
            color=(255,0,0)
            btn_id = 5000
    
            bmp_color = c4d.bitmaps.BaseBitmap()
            bmp_color.Init(w, h)
    
            for y in xrange(w):
                for x in xrange(h):
                    bmp_color.SetPixel(x, y, color[0], color[1], color[2])
    
            bcBitmapButton = c4d.BaseContainer()
            bcBitmapButton[c4d.BITMAPBUTTON_BUTTON] = True
            bmp_btn = self.AddCustomGui(btn_id, c4d.CUSTOMGUI_BITMAPBUTTON, "", c4d.BFH_CENTER|c4d.BFV_CENTER, w, h, bcBitmapButton)
            bmp_btn.SetImage(bmp_color, True)
    
            # Creating a red button through class
            # This part causes the error
    
            red_button = ColorButton()
            red_button.create(w=50,h=50,color=(255,0,0),btn_id=6000)
                    
            return True
        
        def Command(self, id, msg):
    
            return True
        
        def CoreMessage(self, id, data):
    
            return True
    
    class MyMenuPlugin(plugins.CommandData):
    
        dialog = None
        def Execute(self, doc):
        # create the dialog
           if self.dialog is None:
              self.dialog = MyDialog()
    
           return self.dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC, pluginid=PLUGIN_ID, defaultw=200, defaulth=150, xpos=-1, ypos=-1)
    
        def RestoreLayout(self, sec_ref):
        # manage the dialog
           if self.dialog is None:
              self.dialog = MyDialog()
           return self.dialog.Restore(pluginid=PLUGIN_ID, secret=sec_ref)
    
    if __name__ == "__main__":
    
        okyn = plugins.RegisterCommandPlugin(PLUGIN_ID, "Class Button",0, None, "Class Button", MyMenuPlugin())
        if (okyn):
            print "Class Button"
    


  • Hi @bentraje,

    the main issue is that ColorButton is another GeDialog, so that means if you want to draw something you have to open it first.
    Either you have to change it to a SubDialog, this way you can embed it within another GeDialog/SubDialog see gedialog_subdialog_r19.py .
    Or either you have to use the instance of the dialog that is already open to do the draw operation.

    import c4d
    
    class ColorButton(object):
    
        def __init__(self):
            self.width = None
            self.height = None
            self.color = None
            self.color = None
            self.btn_id = 3000
    
    
        def create(self, dlg, w, h, color, btn_id):
    
            self.width = w
            self.height = h
            self.color = color
    
            bmp_color = c4d.bitmaps.BaseBitmap()
            bmp_color.Init(w, h)
    
            for y in xrange(w):
                for x in xrange(h):
                    bmp_color.SetPixel(x, y, color[0], color[1], color[2])
    
            bcBitmapButton = c4d.BaseContainer()
            bcBitmapButton[c4d.BITMAPBUTTON_BUTTON] = True
    
            bmp_btn = dlg.AddCustomGui(btn_id, c4d.CUSTOMGUI_BITMAPBUTTON, "", c4d.BFH_CENTER | c4d.BFV_CENTER, w, h, bcBitmapButton)
    
            bmp_btn.SetImage(bmp_color, True)
    
    class MyDialog(c4d.gui.GeDialog):
    
        def CreateLayout(self):
            # Creating a red button through class
            # This part causes the error
    
            red_button = ColorButton()
            red_button.create(self, w=50,h=50,color=(255,0,0), btn_id=6000)
                    
            return True
    
    

    Now regarding which solution is best, it is up to you, but I will argue that SubDialog is cleaner since Gadget ID become local to this SubDialog, while if you share an instance of the GeDialog, you have to be sure that all ID is unique.

    Hope it makes sense,
    Cheers,
    Maxime.



  • Thanks for the response. The code works as expected.
    For the option, I think I'll go with "use the instance of the dialog" like in your code above. Seems like an easier way to handle and maintain.

    With the AutoID() class you shared, I never had any problem with the ID management now. Hehehe

    BTW, just one thing, in your code you wrote
    class ColorButton(object):. which makes it that you are inheriting a class, correct me if I'm wrong.

    However, it seems like the class ColorButton: seems to work as well

    Is there a particular reason that you included (object) ?



  • https://stackoverflow.com/questions/4015417/python-class-inherits-object
    It's just a "good practice" for python 2.X to always derive from object your BaseClass.

    Cheers,
    Maxime.



  • @m_adam

    Ah. Gotcha. Thanks for the clarification and link.


Log in to reply