Scripted objects: Difference between revisions
(New page: Besides the standard object types such as annotations, meshes and parts objects, FreeCAD also offers the amazing possibility to build 100% python-scripted objects, called Python Features. ...) |
|||
Line 14: | Line 14: | ||
class Box: |
class Box: |
||
def __init__(self, obj): |
def __init__(self, obj): |
||
"Add some custom properties to our box feature" |
"'''Add some custom properties to our box feature'''" |
||
obj.addProperty("App::PropertyLength","Length","Box","Length of the box").Length=1.0 |
obj.addProperty("App::PropertyLength","Length","Box","Length of the box").Length=1.0 |
||
obj.addProperty("App::PropertyLength","Width","Box","Width of the box").Width=1.0 |
obj.addProperty("App::PropertyLength","Width","Box","Width of the box").Width=1.0 |
||
Line 21: | Line 21: | ||
def onChanged(self, fp, prop): |
def onChanged(self, fp, prop): |
||
"Do something when a property has changed" |
"'''Do something when a property has changed'''" |
||
FreeCAD.Console.PrintMessage("Change property: " + str(prop) + "\n") |
FreeCAD.Console.PrintMessage("Change property: " + str(prop) + "\n") |
||
def execute(self, fp): |
def execute(self, fp): |
||
"Do something when doing a recomputation, this method is mandatory" |
"'''Do something when doing a recomputation, this method is mandatory'''" |
||
FreeCAD.Console.PrintMessage("Recompute Python Box feature\n") |
FreeCAD.Console.PrintMessage("Recompute Python Box feature\n") |
||
class ViewProviderBox: |
class ViewProviderBox: |
||
def __init__(self, obj): |
def __init__(self, obj): |
||
"Set this object to the proxy object of the actual view provider" |
"'''Set this object to the proxy object of the actual view provider'''" |
||
obj.addProperty("App::PropertyColor","Color","Box","Color of the box").Color=(1.0,0.0,0.0) |
obj.addProperty("App::PropertyColor","Color","Box","Color of the box").Color=(1.0,0.0,0.0) |
||
obj.Proxy = self |
obj.Proxy = self |
||
def attach(self, obj): |
def attach(self, obj): |
||
"Setup the scene sub-graph of the view provider, this method is mandatory" |
"'''Setup the scene sub-graph of the view provider, this method is mandatory'''" |
||
self.shaded = coin.SoGroup() |
self.shaded = coin.SoGroup() |
||
self.wireframe = coin.SoGroup() |
self.wireframe = coin.SoGroup() |
||
Line 56: | Line 56: | ||
def updateData(self, fp, prop): |
def updateData(self, fp, prop): |
||
"If a property of the handled feature has changed we have the chance to handle this here" |
"'''If a property of the handled feature has changed we have the chance to handle this here'''" |
||
# fp is the handled feature, prop is the name of the property that has changed |
# fp is the handled feature, prop is the name of the property that has changed |
||
l = fp.getPropertyByName("Length") |
l = fp.getPropertyByName("Length") |
||
Line 65: | Line 65: | ||
def getDisplayModes(self,obj): |
def getDisplayModes(self,obj): |
||
"Return a list of display modes." |
"'''Return a list of display modes.'''" |
||
modes=[] |
modes=[] |
||
modes.append("Shaded") |
modes.append("Shaded") |
||
Line 72: | Line 72: | ||
def getDefaultDisplayMode(self): |
def getDefaultDisplayMode(self): |
||
"Return the name of the default display mode. It must be defined in getDisplayModes." |
"'''Return the name of the default display mode. It must be defined in getDisplayModes.'''" |
||
return "Shaded" |
return "Shaded" |
||
def setDisplayMode(self,mode): |
def setDisplayMode(self,mode): |
||
"Map the display mode defined in attach with those defined in getDisplayModes. |
"'''Map the display mode defined in attach with those defined in getDisplayModes.''' |
||
'''Since they have the same names nothing needs to be done. This method is optional'''" |
|||
return mode |
return mode |
||
def onChanged(self, vp, prop): |
def onChanged(self, vp, prop): |
||
"Here we can do something when a single property got changed" |
"'''Here we can do something when a single property got changed'''" |
||
FreeCAD.Console.PrintMessage("Change property: " + str(prop) + "\n") |
FreeCAD.Console.PrintMessage("Change property: " + str(prop) + "\n") |
||
if prop == "Color": |
if prop == "Color": |
||
Line 87: | Line 88: | ||
def getIcon(self): |
def getIcon(self): |
||
"Return the icon in XMP format which will appear in the tree view. This method is |
"'''Return the icon in XMP format which will appear in the tree view. This method is''' |
||
'''optional and if not defined a default icon is shown.'''" |
|||
return """ |
return """ |
||
/* XPM */ |
/* XPM */ |
||
Line 117: | Line 119: | ||
def __getstate__(self): |
def __getstate__(self): |
||
''' |
"'''When saving the document this object gets stored using Python's cPickle module.''' |
||
'''Since we have some un-pickable here -- the Coin stuff -- we must define this method''' |
|||
'''to return a tuple of all pickable objects or None.'''" |
|||
''' |
|||
return None |
return None |
||
def __setstate__(self,state): |
def __setstate__(self,state): |
||
''' |
"'''When restoring the pickled object from document we have the chance to set some internals here.''' |
||
'''Since no data were pickled nothing needs to be done here.'''" |
|||
''' |
|||
return None |
return None |
||
Revision as of 13:17, 17 August 2009
Besides the standard object types such as annotations, meshes and parts objects, FreeCAD also offers the amazing possibility to build 100% python-scripted objects, called Python Features. Those objects will behave exactly as any other FreeCAD object, can be saved in a document and opened on any other installation of FreeCAD, since the python code that defines the object is also saved in the document.
Python Features follow the same rule as all FreeCAD features: they are separated into App and GUI parts. The app part, the Document Object, defines the geometry of our object, while its GUI part, the View Provider Object, defines how the object will be drawn on screen. The View Provider Object, as any other FreeCAD feature, is only available when you run FreeCAD in its own GUI. There are several properties and methods available to build your object. Properties must be of any of the predefined properties types that FreeCAD offers, and will appear in the property view window, so they can be edited by the user. This way, FeaturePython objects are truly and totally parametric. you can define properties for the Object and its ViewObject separately.
Example
The following sample can be found in the src/Mod/TemplatePyMod/FeaturePython.py file:
"Examples for a feature class and its view provider." import FreeCAD, FreeCADGui from pivy import coin class Box: def __init__(self, obj): "Add some custom properties to our box feature" obj.addProperty("App::PropertyLength","Length","Box","Length of the box").Length=1.0 obj.addProperty("App::PropertyLength","Width","Box","Width of the box").Width=1.0 obj.addProperty("App::PropertyLength","Height","Box", "Height of the box").Height=1.0 obj.Proxy = self def onChanged(self, fp, prop): "Do something when a property has changed" FreeCAD.Console.PrintMessage("Change property: " + str(prop) + "\n") def execute(self, fp): "Do something when doing a recomputation, this method is mandatory" FreeCAD.Console.PrintMessage("Recompute Python Box feature\n") class ViewProviderBox: def __init__(self, obj): "Set this object to the proxy object of the actual view provider" obj.addProperty("App::PropertyColor","Color","Box","Color of the box").Color=(1.0,0.0,0.0) obj.Proxy = self def attach(self, obj): "Setup the scene sub-graph of the view provider, this method is mandatory" self.shaded = coin.SoGroup() self.wireframe = coin.SoGroup() self.scale = coin.SoScale() self.color = coin.SoBaseColor() data=coin.SoCube() self.shaded.addChild(self.scale) self.shaded.addChild(self.color) self.shaded.addChild(data) obj.addDisplayMode(self.shaded,"Shaded"); style=coin.SoDrawStyle() style.style = coin.SoDrawStyle.LINES self.wireframe.addChild(style) self.wireframe.addChild(self.scale) self.wireframe.addChild(self.color) self.wireframe.addChild(data) obj.addDisplayMode(self.wireframe,"Wireframe"); self.onChanged(obj,"Color") def updateData(self, fp, prop): "If a property of the handled feature has changed we have the chance to handle this here" # fp is the handled feature, prop is the name of the property that has changed l = fp.getPropertyByName("Length") w = fp.getPropertyByName("Width") h = fp.getPropertyByName("Height") self.scale.scaleFactor.setValue(l,w,h) pass def getDisplayModes(self,obj): "Return a list of display modes." modes=[] modes.append("Shaded") modes.append("Wireframe") return modes def getDefaultDisplayMode(self): "Return the name of the default display mode. It must be defined in getDisplayModes." return "Shaded" def setDisplayMode(self,mode): "Map the display mode defined in attach with those defined in getDisplayModes. Since they have the same names nothing needs to be done. This method is optional" return mode def onChanged(self, vp, prop): "Here we can do something when a single property got changed" FreeCAD.Console.PrintMessage("Change property: " + str(prop) + "\n") if prop == "Color": c = vp.getPropertyByName("Color") self.color.rgb.setValue(c[0],c[1],c[2]) def getIcon(self): "Return the icon in XMP format which will appear in the tree view. This method is optional and if not defined a default icon is shown." return """ /* XPM */ static const char * ViewProviderBox_xpm[] = { "16 16 6 1", " c None", ". c #141010", "+ c #615BD2", "@ c #C39D55", "# c #000000", "$ c #57C355", " ........", " ......++..+..", " .@@@@.++..++.", " .@@@@.++..++.", " .@@ .++++++.", " ..@@ .++..++.", "###@@@@ .++..++.", "##$.@@$#.++++++.", "#$#$.$$$........", "#$$####### ", "#$$#$$$$$# ", "#$$#$$$$$# ", "#$$#$$$$$# ", " #$#$$$$$# ", " ##$$$$$# ", " ####### "}; """ def __getstate__(self): "When saving the document this object gets stored using Python's cPickle module. Since we have some un-pickable here -- the Coin stuff -- we must define this method to return a tuple of all pickable objects or None." return None def __setstate__(self,state): "When restoring the pickled object from document we have the chance to set some internals here. Since no data were pickled nothing needs to be done here." return None def makeBox(): FreeCAD.newDocument() a=FreeCAD.ActiveDocument.addObject("App::FeaturePython","Box") Box(a) ViewProviderBox(a.ViewObject)
Properties
Properties are the true building stones of FeaturePython objects. Through them, the user will be able to interact and modify your object. After creating a new FeaturePython object in your document ( a=FreeCAD.ActiveDocument.addObject("App::FeaturePython","Box") ), you can get a list of the available properties by issuing:
a.supportedProperties()
You will get a list of available properties:
App::Property App::PropertyLists App::PropertyBool App::PropertyFloat App::PropertyFloatList App::PropertyFloatConstraint App::PropertyAngle App::PropertyDistance App::PropertyInteger App::PropertyIntegerConstraint App::PropertyPercent App::PropertyEnumeration App::PropertyIntegerList App::PropertyString App::PropertyStringList App::PropertyLink App::PropertyLinkList App::PropertyMatrix App::PropertyVector App::PropertyVectorList App::PropertyPlacement App::PropertyPlacementLink App::PropertyComplexGeoData App::PropertyColor App::PropertyColorList App::PropertyMaterial App::PropertyPath App::PropertyFile App::PropertyFileIncluded Part::PropertyPartShape Part::PropertyFilletContour Part::PropertyCircle