Basic plugin creation



  • On 13/02/2013 at 02:10, xxxxxxxx wrote:

    Sorry for super-basic questions, but I´m stucked...
    Learning Python without any programming background is giving me a hard time, although a Python for Children book was a great help already ;-)

    Understanding many easy things now, I want to make a first plugin. Nothing of real use, just the same thing a simple user Script can do in plugin form.
    I got so far, that my plugin loads, but no way I could get it to work by using it. Best I got were no errors messages ;-)

    import c4d  
    from c4d import plugins  
    import os  
      
    PLUGIN_ID = 10000010  
    doc = c4d.documents.GetActiveDocument()  
    obj = doc.GetActiveObject()  
      
    class Starter(c4d.plugins.CommandData) :   
      def Execute(self, doc) :   
          obj.SetAbsPos(c4d.Vector(111.0, 22.0, 22.0))  
          c4d.EventAdd()  
      
     if __name__=='__main__':  
      bmp = c4d.bitmaps.BaseBitmap()  
      dir, file = os.path.split(__file__)  
      fn = os.path.join(dir, "res", "Icon.tif")  
      bmp.InitWith(fn)  
      print "transformer_testloaded."  
      result = plugins.RegisterCommandPlugin(PLUGIN_ID, "transformer_test", 0, bmp, "transformer_test", Starter())  
    

    And if anybody knows a good tutorial on plugin creation, or a very well documented small plugin, I´d be happy :-)
    Thanks



  • On 13/02/2013 at 04:06, xxxxxxxx wrote:

    So what's your actual problem? There's nothing specific in your question, actually there isn't
    even a question-mark.

    PS: The two lines after PLUGIN_ID = 10000010 are senseless, the result will not be what you
    expect it to be when your plugin executes. You probably want to use doc.GetActiveObject() from
    withtin the Execute() method.

    -N



  • On 13/02/2013 at 06:52, xxxxxxxx wrote:

    Sorry next time I´ll be more specific...
    Problem was that I had no real clue why  it wasn´t working,  not a problem with a user script.
    But you pointing out the wrong position of the variables already helped.
    Now I got it to work, and I learned lots, but I still don´t understand why I have to put the variables two times in there?
    Probably missing some real basic concept here...

    import c4d  
    import random  
    from c4d import plugins  
    import os  
      
    PLUGIN_ID = 10000010  
      
    class Starter(c4d.plugins.CommandData) :  
      doc = c4d.documents.GetActiveDocument()  
      obj = doc.GetActiveObject()                         #Why define Variables here and under Execute again?  
      rnd = random.random()  
      
      def Execute(self, doc) :    
          true_v = True      
          obj = doc.GetActiveObject()  
          rnd = random.random()  
          if obj != None:              
              obj.SetAbsPos(c4d.Vector((rnd*100), 0, 0))    
          else:  
              print ("Nothing")  
          c4d.EventAdd()  
          return true_v    
      
      
    if __name__ =='__main__':  
      bmp = c4d.bitmaps.BaseBitmap()  
      dir, file = os.path.split(__file__)  
      fn = os.path.join(dir, "res", "Icon.tif")  
      bmp.InitWith(fn)  
      print "transformer_testloaded."  
      result = plugins.RegisterCommandPlugin(PLUGIN_ID, "transformer_test", 0, bmp, "transformer_test", Starter())
    


  • On 13/02/2013 at 07:13, xxxxxxxx wrote:

    You can remove the 3 lines after class Starter(c4d.plugins.CommandData) :.
    😉



  • On 13/02/2013 at 07:36, xxxxxxxx wrote:

    Ohoh I should stop for today 🤢
    In this older version without an if I had to keep them both though:

    class Starter(c4d.plugins.CommandData) :  
      
      true_v = True  
      # doc = c4d.documents.GetActiveDocument()  
      # obj = doc.GetActiveObject()               
      # rnd = random.random()  
      
      print obj  
      def Execute(self, doc) :               
          obj = doc.GetActiveObject()               
          rnd = random.random()  
          obj.SetAbsPos(c4d.Vector((rnd*100), 0, 0))         
          c4d.EventAdd()  
          return self.true_v 
    

    Anyway, thanks for the patience ;)



  • On 13/02/2013 at 07:42, xxxxxxxx wrote:

    Just out of curiousity: Why do you use the true_v variable, when it is never assigned another
    value but True?

    This should work fine as well:

    class Starter(c4d.plugins.CommandData) :
      
        def Execute(self, doc) :             
            obj = doc.GetActiveObject()
            if not obj:
                print "Nothing"
                return True
      
            rnd = random.random()
            obj.SetAbsPos(c4d.Vector((rnd*100), 0, 0))       
            c4d.EventAdd()
            return True
    

    -N



  • On 13/02/2013 at 08:15, xxxxxxxx wrote:

    Google the word "scope". This will tell you why you had to have the same code in two different places.

    -ScottA



  • On 13/02/2013 at 08:51, xxxxxxxx wrote:

    is was not so much a scope problem, more a time of execution problem. obj should 
    have been always None for his first example, unless he started the c4d with an saved
    document which already contained a selection. doc would also have been always the 
    startup document. or what do you mean with scope in that case ?

    there are also some special methods in python which are defined by a double underline
    pre- and postfix. you should take a look into them. __init__ can be used in a way you
    would normally use a class constructor. it helps to make visually more clear which
    variables are visible for all members of the class and that alle values defined here are
    tied to the time of instantiation (which would be for a plugin class the start of c4d).

    http://docs.python.org/2/reference/datamodel.html#object.__init__



  • On 13/02/2013 at 23:53, xxxxxxxx wrote:

    Thanks everybody, I still struggle understanding classes, I got why not to put variables before the class, and thanks for pointing out returning True instead of a senseless variable. Although I´m sure I tried that  ;)

    Now I tried to make use of  __init__ but doesn´t matter what,  it doesn´t work:
    For the understanding, when the class is called, __init__  assigns variables within this class?
    I read up about it but still...
    So what I did wrong here? Error message in red... Or is it complete nonsense?

    class Starter(c4d.plugins.CommandData) :  
      def __init__ (self) :  
          self.doc_a  = c4d.documents.GetActiveDocument()  
          self.obj    = doc_a.GetActiveObject()  
          self.rnd    = random.random()         
      
      
      def Execute(self, doc) :        
          if not obj:   
              print ("Nothing Selected")  
              return True             
          obj.SetAbsPos(c4d.Vector((rnd*100), 0, 0))    
          c4d.EventAdd()  
          return True   
      
    # NameError: global name 'doc_a' is not defined
    


  • On 14/02/2013 at 00:21, xxxxxxxx wrote:

    Hi Schnups,

    I'm wondering where you are reading about classes, it obviously is teaching you wrong. In Python,
    you can assign any variable to your own class, not necessarily in the __init__() method which is
    only called when the instance has just been created. But when you assign the instance the
    variable, you also have to read it from it.

    class Foo(object) :
      
        def __init__(self, abc) :
            self.abc = abc
      
        def get_abc(self) :
            return self.abc
      
        def get_other(self) :
            return self.other
      
    f = Foo("hello schnupsi") # creates a new instance and calls __init__() on it
    print f.abc # Prints "hello schnupsi"
    print f.get_abc() # Prints "hello schnupsi"
    print f.get_other() # This will NOT WORK, `f` does not have an attribute `other`
      
    f.other = "other text"
    print f.other # Prints "other text"
    print f.get_other() # Prints "other text"
    

    You should really lay down the book you're currently reading at take a look at the official Python
    tutorial, which is imho the best place to start programming with Python.

    See: http://docs.python.org/2.6/tutorial/index.html

    PS: I still don't understand why you want to use the document that is active at the time
    an instance of your CommandData subclass is created, which is at registration-time. The document
    you obtain might either not be valid at the time Execute() is called (which is when you click on your
    plugin in Cinema's GUI) or simply not be the active document anymore.

    -Niklas



  • On 14/02/2013 at 01:17, xxxxxxxx wrote:

    "hello schnupsi" 😂



  • On 14/02/2013 at 01:35, xxxxxxxx wrote:

    Uups, had your name wrong in mind while writing that. 😊



  • On 14/02/2013 at 01:47, xxxxxxxx wrote:

    Ahh, thanks Niklasi ;-) that helped...

    I didn´t want to get the variables at creation time. I thought before, the class is somehow created while executing...

    So, if I´ve got it right: The class, as everything before and after, is being "executed" while plugin loading up. Putting a function, variable etc. here, you want to execute by using the plugin doesn´t make sense.
    Only the execute triggers its defined code, but I can also use other pre-defined functions in here too, right?

    I guess the jump from little user scripts to the interface plugins I plan is a bit high.
    The Python Tutorial is on my scope now first...



  • On 14/02/2013 at 04:07, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    class Starter(c4d.plugins.CommandData) :  
      def __init__ (self) :  
          self.doc_a  = c4d.documents.GetActiveDocument()  
            #you refer to the variable of the class, so you have to reference "self."  
          self.obj    = self.doc_a.GetActiveObject()  
          self.rnd    = random.random()         
     
     
      def Execute(self, doc) :        
          if not obj:   
              print ("Nothing Selected")  
              return True             
          obj.SetAbsPos(c4d.Vector((rnd*100), 0, 0))    
          c4d.EventAdd()  
          return True   
     
    # NameError: global name 'doc_a' is not defined
    

    What you wrote refers to a variable doc_a which is known for all funtcions, since you haven't declared that it comes from some owner, but such a variable doesn't exist. That's what the error message says "No global variable of that name"

    Greetings
    Nachtmahr



  • On 16/02/2013 at 02:44, xxxxxxxx wrote:

    Ok, roger that :)

    Is it possible give a plugin a background behaviour in a similar way the Script Log works?
    Not in a list, just that it writes the string of the last command called to a variable, (like the entries which also shows up in the Script Log entry)?

    If it´s very complicated don´t worry...



  • On 16/02/2013 at 03:36, xxxxxxxx wrote:

    Unfortunately there is not (yet, from Python).

    -N



  • On 16/02/2013 at 04:04, xxxxxxxx wrote:

    What a pity, I wanted to do a "Repeat last Command" plugin, like Max and Maya have. Which would check with a list of chosen c4d commands to repeat them easily.

    Well, another question for future plugins:
    It is possible to update a plugin-gui spinner, which for instance changes a position, in realtime, without the need of an apply button? Not in an object or tag plugin.
    Don´t need to know how, just if...

    Thanks for being such a big helper around here Niklas :)



  • On 16/02/2013 at 07:49, xxxxxxxx wrote:

    what do you mean with   Not in an object or tag plugin ? a dialog or a shader/tool ?
    for dialogs, use the command/coremessage method to write/read data from/into 
    your dialog.for descriptions it is allso possible, but actually not the way things are 
    intended to be done. the message/getdenabling methods could be here a suiteable 
    place to implement such behaviour. for certain behaviours you would have to write a 
    message helper plugin to notify your plugins when they have to update themself.



  • On 16/02/2013 at 08:50, xxxxxxxx wrote:

    A bit confusing written, sorry. I meant the python tag or generator with user data by not in a tag....

    What Im planning once my skill is good enough, is to do a much improved coordinate manager, which first of all, has an auto update, so you see the changes while adjusting.



  • On 16/02/2013 at 08:57, xxxxxxxx wrote:

    So, you'll want to make a dialog. This is perfectly possible: once a value is changed by the user, you will be
    notified about this change and can react on it.

    -N


Log in to reply