Tips and Tricks: Reading the SDK

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 11/04/2011 at 17:11, xxxxxxxx wrote:

Since many people (besides me) have problems understanding how to read the SDK.
Should we have a thread that has tips on how to read it?

For example.
This is something that I learned that's very important in getting the most out of the SDK:

Many things in the Python SDK need to be created (instantiated) first before you can use the methods in that class.
So to create an instance of a class. You look at the top of the SDK where it's say's something like this in grey:

-class c4d.utils.Neighbor  
-class c4d.bitmaps.BaseBitmap
-class c4d.utils.SplineHelp

Then you assign a variable to this class like this:
nb = utils.Neighbor               #assigns a variable to the Neighbor class
bmp = bitmaps.BaseBitmap  #assigns a variable to the Bitmap class
sh = c4d.utils.SplineHelp()    #assigns a variable to the SplineHelp

Once you've got a variable assigned to your class. You can then initialize it by using that variable with the init() function for that class. Like this:

nb.Init(obj) #obj would be a variable that holds the object we're working on
bmp.InitWith(path) #Path would be a variable that holds a file path
length.Init(op,0)# Initializes the spline object(op) and the first spline segment

Notice: We don't   use _Init()_
Instead we look for the Init() function listed in the SDK under a particular class that has either nothing in it(). Or some parameters in it by default.

Now that we have the class defined with a variable. And the class is instantiated using that variable. We can now use that to call to all of the many methods associated with each class in the SDK like this:

nb.GetPointPolys(PointIndex) # Gets the neighboring polygons found in variable PointIndex
bmp.GetSize() #Gets the pixel size of an image
sh.GetSegmentLength(0)#Gets the length of the first segment

Knowing how to create and initialize classes like this is crucial in using the C4D Python SDK.
Because in many cases. You can't get access to all of the wonderful methods until you instantiate the class first.

-ScottA

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 11/04/2011 at 21:40, xxxxxxxx wrote:

Many things in the Python SDK need to be created (instantiated) first before you can use the methods in that class.
So to create an instance of a class. You look at the top of the SDK where it's say's something like this in grey:

Of course! You must see the difference between a module and a class.

Once you've got a variable assigned to your class. You can then initialize it by using that variable with the init() function for that class. Like this:

Not every class has got an own 'Init()' method. This is just for classes that need to be initialised with any values, that can be flushed, so that you can initialise them again.

nb = utils.Neighbor               #assigns a variable to the Neighbor class
bmp = bitmaps.BaseBitmap  #assigns a variable to the Bitmap class
sh = c4d.utils.SplineHelp()    #assigns a variable to the SplineHelp

In the first 2 lines you do *not* instantiate the classes 'Neighbour' and 'BaseBitmap', you assign the vonstructors new variables.

That's the difference:

from c4d import utils  
  
neighbor_constructor = utils.Neighbor  
  
neihgbor_instance = utils.Neighbor()  
neihgbor_instance.Init(op)  
  
neihgbor_instance.GetPointPolys(1)  
neighbor_constructor.GetPointPolys(1)      #raises an error

This is a very handy feature of Python:

from c4d.gui import MessageDialog as MsgD  
MsgD("Hi, I'm a MessageDialog !")
import c4d  
from c4d import BaseObject as BO  
BO(c4d.Ocube)  
"""This is the same as: """  
import c4d  
BO = c4d.BaseObject  
BO(c4d.Ocube)
"""You can also overload functions"""  
import c4d  
  
def do(userfunc,*userargs) :  
  op = c4d.BaseObject(c4d.Ocube)  
  userfunc(op,*userargs)  
  
def myfunction(op,vec) :  
  op.SetAbsPos(vec)  
  
def main() :  
  do(myfunction,c4d.Vector(0,300,700))  
  
main()

Cheers, Niklas

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 12/04/2011 at 11:05, xxxxxxxx wrote:

This is a small tip. But trips up many people.
Many things need to have a c4d. prefix to work. And it's easy to forget it.

The Error you'll get for this is:
NameError: global name "item" Not Defined     #  item is whatever you're working on at the time

This is the same error you get if you forget to declare a variable. But most people spot that kind of mistake fairly easy.
The missing c4d. prefix is a little bit more subtle and harder to spot.

-ScottA

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 15/04/2011 at 08:50, xxxxxxxx wrote:

I didn't see any examples of creating menus and sub menus in the SDK.
So here is an entire plugin example that shows how to create them. And does some other common tasks.

  
import os  
import sys  
import c4d  
from c4d import plugins, utils, bitmaps, gui, documents  
  
Plugin_ID=1000009 # Testing id ONLY!!!!!!!   
  
 #enums  
MENU_ITEM1 = 1  
MENU_ITEM2 = 2   
MENU_ITEM3 = 3   
MENU_ITEM4 = 4  
RESET_BUTTON = 5     
   
   
#---------------------------------------------------  
#   MyDialog_Gui class --- where GUI items are added  
#---------------------------------------------------  
  
class MyDialog_Gui(gui.GeDialog) :  
   
 def CreateLayout(self) :  
   
 #This is the first menu code  
  self.MenuFlushAll();      
  self.MenuSubBegin("Menu1")              
  self.MenuAddString(MENU_ITEM1,"item1")  
  self.MenuAddString(MENU_ITEM2,"item2")  
  self.MenuAddSeparator()  
  self.MenuSubBegin("SubMenu1")  
  self.MenuAddCommand(1001153) # Creates an atom object                  
  self.MenuSubBegin("SubMenu2")  
  self.MenuAddCommand(1001154) # Creates a double circle object                      
  self.MenuSubEnd()  
  self.MenuSubEnd()  
  self.MenuSubEnd()  
  self.MenuFinished() #Ends the first menu & submenu list    
  
  #This is the second menu code   
  #Notice that we don't make another MenuFlushAll() function   
  self.MenuSubBegin("Menu2")              
  self.MenuAddString(MENU_ITEM3,"test1")  
  self.MenuAddString(MENU_ITEM4,"test2")  
  self.MenuAddSeparator()  
  self.MenuSubBegin("SubMenu1")  
  self.MenuAddCommand(5159) # Creates a Cube primitive                  
  self.MenuSubBegin("SubMenu2")  
  self.MenuAddCommand(5160) # Creates a Sphere primitive                      
  self.MenuSubEnd()  
  self.MenuSubEnd()  
  self.MenuSubEnd()  
  self.MenuFinished() #Ends the second menu & submenu list   
    
  self.GroupBeginInMenuLine() #Adds the Button to the menu area of the dialog window  
  self.AddButton(RESET_BUTTON, c4d.BFH_CENTER, 60, 10, name="Reset") #id, flags, width, height, caption   
  self.GroupEnd() #Ends the group formatting   
    
   
  self.GroupBegin(0, c4d.BFH_SCALEFIT|c4d.BFH_SCALEFIT, 1, 3, "Group Title",0) #id, flags, columns, rows, grouptext, groupflags  
  self.GroupBorder(c4d.BORDER_BLACK)  
  self.GroupBorderSpace(5, 20, 5, 20) #Left, top, Right, Bottom   
  self.SetTitle("myPythonDialog")    
  self.AddStaticText(4001,c4d.BFH_LEFT,50,10,"input",c4d.BORDER_NONE) #id, flags, height, width, text, borderstyle                                        
  self.AddEditText(4002,c4d.BFH_SCALEFIT,4,10,0) #id, flags, height, width, password     
  self.AddEditText(4003,c4d.BFH_SCALEFIT,2,10,0) #id, flags, height, width, password       
  self.AddButton(1001, c4d.BFH_CENTER, 100, 10, name="Execute X-Ray") #Puts the button in the menu bar  
    
  self.GroupEnd()  
  return True   
  
#--------------------------------------------------------------------------  
#    MyDialog_Gui method --- where gui items are set up with default values  
#--------------------------------------------------------------------------   
   
 def InitValues(self) :  
self.SetString(4002,"Waiting") #Sets the text inside of the field when the plugin opens  
self.SetString(4003,"Waiting") #Sets the text inside of the field when the plugin opens  
return True  
  
#---------------------------------------------------------------------------------------------  
#   MyDialog_Gui method --- Executes your code when GUI is used. Put your python code in here  
#---------------------------------------------------------------------------------------------     
    
 def Command(self, id, msg) :  
doc = documents.GetActiveDocument()   
op = doc.GetActiveObject()   
if id == 1001:  
  print "Button was pushed"  
  if not op:  
     gui.MessageDialog("Select an object first!")  
     return True  
  op[c4d.ID_BASEOBJECT_XRAY]=1  
  self.SetString(4002,"Button Worked!") #Sets the text inside of the field when the button is pushed  
  self.SetString(4003,"Congradulations!") #Sets the text inside of the field when the button is pushed  
  #gui.MessageDialog("Button was pushed") # Makes a pop up message appear whe the button is pushed  
    
if id == RESET_BUTTON:     
  self.SetString(4002,"Waiting") #ReSets the text  
  self.SetString(4003,"Waiting") #ReSets the text     
  op[c4d.ID_BASEOBJECT_XRAY]=0 #Turns the Xray option off  
c4d.EventAdd()  
  
return True  
    
    
    
#---------------------------------------------------------------  
#   MyDialog_Main --- Where the plugin stuff happens--Don't edit  
#---------------------------------------------------------------  
class myDialog_Main(plugins.CommandData) :  
 dialog = None  
    
 def Execute(self, doc) :  
  # create the dialog  
  if self.dialog is None:  
     self.dialog = MyDialog_Gui()  
  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 nonmodal dialog  
  if self.dialog is None:  
     self.dialog = MyDialog_Gui()  
  return self.dialog.Restore(pluginid=Plugin_ID, secret=sec_ref)  
   
  
if __name__ == "__main__":  
 path, fn = os.path.split(__file__)  
 bmp = bitmaps.BaseBitmap()  
 bmp.InitWith(os.path.join(path, "res/icons/", "None"))  
 plugins.RegisterCommandPlugin(Plugin_ID, "myPythonDialog",0,None,"", myDialog_Main())  

-ScottA

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 18/05/2011 at 10:25, xxxxxxxx wrote:

Changing the display filter options is listed in the SDK under "BaseDocument".
But I couldn't anything about the Selection filters. So here's how to manipulate those options with python.

Here's a way to see which options are enabled:

import c4d  
from c4d import gui  
  
def main() :  
 bc = doc.GetData()  
 sf = bc.GetLong(c4d.DOCUMENT_SELECTIONFILTER) #Get the filter bit mask  
 if not(sf & c4d.SELECTIONFILTERBIT_NULL) : print "Null Enabled"  
 if not(sf & c4d.SELECTIONFILTERBIT_POLYGON) : print "Polygon Enabled"  
 if not(sf & c4d.SELECTIONFILTERBIT_SPLINE) : print "Spline Enabled"  
 if not(sf & c4d.SELECTIONFILTERBIT_GENERATOR) : print "Generator Enabled"  
 if not(sf & c4d.SELECTIONFILTERBIT_HYPERNURBS) : print "HyperNurbs Enabled"  
 if not(sf & c4d.SELECTIONFILTERBIT_DEFORMER) : print "Deformer Enabled"  
 if not(sf & c4d.SELECTIONFILTERBIT_CAMERA) : print "Camera Enabled"  
 if not(sf & c4d.SELECTIONFILTERBIT_LIGHT) : print "Light Enabled"  
 if not(sf & c4d.SELECTIONFILTERBIT_SCENE) : print "Scene Enabled"  
 if not(sf & c4d.SELECTIONFILTERBIT_PARTICLE) : print "Particle Enabled"  
 if not(sf & c4d.SELECTIONFILTERBIT_JOINT) : print "Joint Enabled"  
   
if __name__=='__main__':  
  main()

These two scripts show how to turn one of the selections on or off:

#This script turns the polygon option OFF  
  
import c4d  
from c4d import gui  
  
def main() :  
 bc = doc.GetData()#Get the document's container  
 sf = bc.GetLong(c4d.DOCUMENT_SELECTIONFILTER) #Get the filter bit mask  
  
 if not(sf & c4d.SELECTIONFILTERBIT_POLYGON) : #If the option is ON  
  f = sf | c4d.SELECTIONFILTERBIT_POLYGON #Change the polygon option's Bit in memory only  
  bc.SetLong(c4d.DOCUMENT_SELECTIONFILTER, f) #Use the Bit info to change the container in memory only  
  doc.SetData(bc) #Execute the changes made to the container from memory  
 c4d.EventAdd()  
  
if __name__=='__main__':  
  main()  
  
##################################################################################  
##################################################################################  
  
#This script turns the polygon option ON  
  
import c4d  
from c4d import gui  
  
def main() :  
 bc = doc.GetData()#Get the document's container  
 sf = bc.GetLong(c4d.DOCUMENT_SELECTIONFILTER) #Get the filter bit mask  
  
 if (sf & c4d.SELECTIONFILTERBIT_POLYGON) : #If the option is OFF  
  f = sf &~ c4d.SELECTIONFILTERBIT_POLYGON #Change the polygon option's Bit in memory only  
  bc.SetLong(c4d.DOCUMENT_SELECTIONFILTER, f) #Use the Bit info to change the container in memory only  
  doc.SetData(bc) #Execute the changes made to the container from memory  
 c4d.EventAdd()  
  
if __name__=='__main__':  
  main()

Credit goes to the guys in the C++ forum for helping me figure this one out.

-ScottA