Create a FeaturePython object part I/fr: Difference between revisions

From FreeCAD Documentation
(Updating to match new version of source page)
No edit summary
 
(107 intermediate revisions by 2 users not shown)
Line 1: Line 1:
<languages/>
<languages/>


{{Docnav/fr
<div class="mw-translate-fuzzy">
{{docnav/fr
|[[PySide/fr|PySide]]
|[[PySide/fr|PySide]]
|[[Creating a FeaturePython Box, Part II/fr|Création d'un Box FeaturePython, Part II]]
|[[Create_a_FeaturePython_object_part_II/fr|Créer un objet FeaturePython partie II]]
}}
}}
</div>

== Introduction ==


{{TOCright}}
{{TOCright}}


==Introduction==
<div class="mw-translate-fuzzy">

Les objets FeaturePython (également appelés «objets scriptés») offrent aux utilisateurs la possibilité d'étendre FreeCAD avec des objets qui s'intègrent de manière transparente dans le framework FreeCAD.
Les objets FeaturePython (également appelés [[Scripted_objects/fr|Objets créés par script]]) offrent aux utilisateurs la possibilité d'étendre FreeCAD avec des objets qui s'intègrent de manière transparente dans le framework FreeCAD.
</div>


<div class="mw-translate-fuzzy">
Cela favorise:
Cela favorise:
* '''Le prototypage rapide''' de nouveaux objets et outils avec des classes personnalisées de Python.
*Le prototypage rapide de nouveaux objets et outils avec des classes personnalisées de Python.
* '''La sérialisation''' via les objets 'App::Property' ''sans incorporer de scripts'' dans le fichier document FreeCAD.
* Sauvegarde et restauration des données (également appelées sérialisation) via des objets {{incode|App::Property}} sans intégrer de script dans le fichier de document FreeCAD.
* '''Une liberté créative''' pour adapter FreeCAD à n'importe quelle tâche!
*Une liberté créative pour adapter FreeCAD à n'importe quelle tâche.
</div>

Ce wiki vous fournira une compréhension complète de l'utilisation des objets FeaturePython et des classes Python personnalisées dans FreeCAD. Nous allons construire un exemple complet et fonctionnel d'une classe personnalisée FeaturePython, identifiant tous les principaux composants et comprendre de manieère fine dont tout cela fonctionne au fur et à mesure.

=== Comment ça marche? ===


Sur cette page, nous allons construire un exemple de travail d'une classe personnalisée FeaturePython, en identifiant tous les composants principaux et en comprenant comment tout fonctionne au fur et à mesure.
FreeCAD est fourni avec un certain nombre de types d'objets par défaut pour gérer différents types de géométrie. Certains d'entre eux ont des alternatives 'FeaturePython' qui permettent la personnalisation de l'utilisateur avec une classe python personnalisée.


<span id="How_does_it_work?"></span>
La classe personnalisée de Python prend simplement une référence à l'un de ces objets et le modifie de plusieurs façons. Par exemple, la classe Python peut ajouter des propriétés directement à l'objet, en modifiant d'autres propriétés lorsqu'il est recalculé ou en le liant à d'autres objets. De plus, la classe Python implémente certaines méthodes pour lui permettre de répondre aux événements du document, ce qui permet de piéger les changements de propriétés des objets et les recalculs du document.
== Comment ça marche? ==


FreeCAD est livré avec un certain nombre de types d'objets par défaut pour gérer différents types de géométrie. Certains d'entre eux ont des alternatives "FeaturePython" qui permettent une personnalisation avec une classe Python définie par l'utilisateur.
Il est important de se rappeler, cependant, que pour autant que l'on puisse accomplir avec des classes personnalisées et des objets FeaturePython, quand vient le temps d'enregistrer le document, '''seul l'objet FeaturePython lui-même est sérialisé'''. La classe personnalisée et son état ne sont pas conservés entre les rechargements de documents. Cela nécessiterait d'incorporer un script dans le fichier de document FreeCAD, ce qui pose un risque de sécurité important, tout comme les risques posés par [https://www.howtogeek.com/171993/macros-explained-why-microsoft-office-files-can-be-dangerous/ embedding VBA macros in Microsoft Office documents].


Cette classe Python personnalisée prend une référence à l'un de ces objets et le modifie. Par exemple, la classe Python peut ajouter des propriétés à l'objet ou le lier à d'autres objets. De plus, la classe Python peut implémenter certaines méthodes pour permettre à l'objet de répondre aux événements du document, ce qui permet de piéger les modifications de propriété de l'objet et de recalculer le document.
Ainsi, un objet FeaturePython existe finalement en dehors de son script. L'inconvénient posé par le fait de ne pas empaqueter le script avec l'objet dans le fichier de document est bien moindre que le risque posé par l'exécution d'un fichier incorporé avec un script inconnu. Cependant, le chemin du module de script est stocké dans le fichier de document. Par conséquent, un utilisateur n'a qu'à installer le code de classe python personnalisé en tant que module importable suivant la même structure de répertoires pour retrouver la fonctionnalité perdue.


Lorsque vous travaillez avec des classes personnalisées et des objets FeaturePython, il est important de savoir que la classe personnalisée et son état ne sont pas enregistrés dans le document car cela nécessiterait l'incorporation d'un script dans un fichier de document FreeCAD, ce qui poserait un risque de sécurité important. Seul l'objet FeaturePython lui-même est enregistré (sérialisé). Mais comme le chemin du module de script est stocké dans le document, un utilisateur n'a qu'à installer le code de classe Python personnalisé en tant que module importable, suivant la même structure de dossier, pour retrouver la fonctionnalité perdue.
== Configuration de votre environnement de développement ==


[[#top|En haut]]
Pour commencer, les classes d'objets FeaturePython doivent agir comme des modules importables dans FreeCAD. Cela signifie que vous devez les placer dans un chemin qui existe dans votre environnement Python (ou l'ajouter spécifiquement). Pour les besoins de ce tutoriel, nous allons utiliser le dossier Macro utilisateur FreeCAD, mais si vous avez une autre idée en tête, n'hésitez pas à l'utiliser à la place!


<span id="Setting_things_up"></span>
<div class="mw-translate-fuzzy">
== Mise en place ==
Si vous ne savez pas où se trouve le dossier Macro FreeCAD, saisissez 'FreeCAD.getUserMacroDir(True)' dans la console Python de FreeCAD. L'endroit est configurable mais, par défaut, pour s'y rendre:
* Windows: tapez '%APPDATA%/FreeCAD/Macro' dans la barre de chemin de fichier en haut de l'Explorateur
* Linux: accédez à /home/USERNAME/.FreeCAD/Macro
* Mac: accédez à /Users/USERNAME/Library/Preferences/FreeCAD/Macro
</div>


Les classes d'objets FeaturePython doivent agir comme des modules importables dans FreeCAD. Cela signifie que vous devez les placer dans un chemin qui existe dans votre environnement Python (ou l'ajouter spécifiquement). Pour les besoins de ce tutoriel, nous allons utiliser le dossier Macro utilisateur FreeCAD, mais si vous avez une autre idée en tête, n'hésitez pas à l'utiliser à la place!
<div class="mw-translate-fuzzy">
Maintenant, nous devons créer des fichiers.
* Dans le dossier Macro, créez un nouveau dossier appelé '''fpo'''.
* Dans le dossier fpo, créez un fichier vide: '''__init__.py'''.
* Dans le dossier fpo, créez un nouveau dossier appelé '''box'''.
* Dans le dossier de la boîte, créez deux fichiers: '''__init__.py''' et '''box.py''' (laissez les deux vides pour l'instant)
</div>


Si vous ne savez pas où se trouve le dossier des Macro de FreeCAD, tapez {{incode|FreeCAD.getUserMacroDir(True)}} dans la [[Python_console/fr|console Python]] de FreeCAD :
=== Notes ===
* Sous Linux, il s'agit généralement de {{FileName|/home/<username>/.local/share/FreeCAD/Mod/}} ({{VersionPlus/fr|0.20}}) ou {{FileName|/home/<username>/.FreeCAD/Mod/}} ({{VersionMinus/fr|0.19}}).
* Sous Windows, c'est {{FileName|%APPDATA%\FreeCAD\Macro\}}, généralement {{FileName|C:\Users\<username>\Appdata\Roaming\FreeCAD\Macro\}}.
* Sous macOS, il s'agit généralement de {{FileName|/Users/<username>/Library/Application Support/FreeCAD/Macro/}}.


Maintenant, nous devons créer des fichiers :
<div class="mw-translate-fuzzy">
*Dans le dossier {{FileName|Macro}}, créez un nouveau dossier appelé {{FileName|fpo}}.
Remarques:
*Dans le dossier {{FileName|fpo}}, créez un fichier vide : {{FileName|__init__.py}}.
* Le dossier '''fpo''' fournit un endroit propice pour jouer avec les nouveaux objets FeaturePython et le dossier '''box''' est le module dans lequel nous travaillerons.
*Dans le dossier {{FileName|fpo}}, créez un nouveau dossier appelé {{FileName|box}}.
* ''''__init__.py''' indique à Python que dans le dossier se trouve un module importable et '''box.py''' sera le fichier de classe pour notre nouvel objet FeaturePython.
*Dans le dossier {{FileName|box}}, créez deux fichiers : {{FileName|__init__.py}} et {{FileName|box.py}} (laissez les deux cases vides pour l'instant).
</div>


La structure de votre répertoire devrait ressembler à ceci:
La structure de votre dossier devrait ressembler à ceci :


Macro/
.FreeCAD
|--> Macro
|--> fpo/
|--> fpo
|--> __init__.py
|--> box/
|--> __init__.py
|--> __init__.py
|--> box
|--> box.py
|--> __init__.py
|--> box.py


Le dossier {{FileName|fpo}} est l'endroit pour jouer avec les nouveaux objets FeaturePython et le dossier {{FileName|box}} est le module dans lequel nous allons travailler. {{FileName|__init__.py}} indique à Python qu'il y a un module importable dans le dossier et {{FileName|box.py}} sera le fichier de classe pour notre nouvel objet FeaturePython.
Avec nos chemins de modules et fichiers créés, assurez-vous que FreeCAD est correctement configuré:


Une fois nos chemins et fichiers de module créés, nous assurons que FreeCAD est correctement configuré :
<div class="mw-translate-fuzzy">
* Démarrez FreeCAD (s'il n'est pas déjà ouvert)
* Démarrez FreeCAD (si vous ne l'avez pas déjà fait).
* Activer la console Python et les vues de rapport ('''Affichage -> Panneaux -> Vue rapport''' et '''console Python''') [[FreeCAD Scripting Basics/fr|(FreeCAD Débuter avec les scripts)]]
* Activez la [[Report_view/fr|Vue rapport]] ({{MenuCommand|Affichage Panneaux Vue rapport}}).
* Activez la [[Python_console/fr|console Python]] ({{MenuCommand|Affichage → Panneaux → Console Python}}) voir [[FreeCAD_Scripting_Basics/fr|FreeCAD Scripting Basics]].
* Dans votre éditeur de code préféré, accédez au dossier '''/Macro/fpo/box''' et ouvrez '''box.py'''
</div>


Enfin, naviguez jusqu'au dossier {{FileName|Macro/fpo/box}} et ouvrez {{FileName|box.py}} dans votre éditeur de code préféré. Nous ne modifierons que ce fichier.
Il est temps d'écrire du code!


[[#top|En haut]]


<span id="A_FeaturePython_object"></span>
-----
==Un objet FeaturePython==


Commençons par écrire notre classe et son constructeur :
== Un objet FeaturePython très basique ==


Commençons par écrire notre classe et son constructeur:
{{Code|code=
{{Code|code=
class box():
class box():
def __init__(self, obj):
"""
Constructor
Arguments
---------
- obj: an existing document object or an object created with FreeCAD.Document.addObject('App::FeaturePython', '{name}').
"""


self.Type = 'box'
def __init__(self, obj):
"""
obj.Proxy = self
Default constructor
"""

self.Type = 'box'

obj.Proxy = self
}}
}}


'''La méthode {{incode|__init__()}} se décompose comme suit:'''


{|class="wikitable" cellpadding="5px" width="100%"
<div class="mw-translate-fuzzy">
|style="width:25%" | {{incode|def __init__(self, obj):}}
'''La méthode breakdown <code>__init__()</code>'''
|style="width:75%" | Les paramètres font référence à la classe Python elle-même et à l'objet FeaturePython auquel elle est attachée.
{|class="wikitable" cellpadding="5" style="margin-left: 15px; margin-right: 5px"
|style="width:30%" | <code>def __init__(self, obj):</code> || Les paramètres font référence à la classe Python elle-même et à l'objet FeaturePython auquel elle est attachée.
|-
|-
| {{incode|self.Type <nowiki>=</nowiki> 'box'}}
|<code> self.Type = 'box'</code> || Définition de chaîne du type Python personnalisé.
| Définition de chaîne du type Python personnalisé.
|-
|-
| {{incode|obj.Proxy <nowiki>=</nowiki> self}}
|<code> obj.Proxy = self</code> || Stocke une référence à l'instance Python dans l'objet FeaturePython.
| Stocke une référence à l'instance Python dans l'objet FeaturePython.
|}
|}
</div>


Ajoutez le code suivant en haut du fichier :


<div class="mw-translate-fuzzy">
Dans le fichier '''box.py''' en haut, ajoutez le code suivant:
</div>
{{Code|code=
{{Code|code=
import FreeCAD as App
import FreeCAD as App

def create(obj_name):
def create(obj_name):
"""
"""
Object creation method
Object creation method
"""
"""

obj = App.ActiveDocument.addObject('App::FeaturePython', obj_name)
obj = App.ActiveDocument.addObject('App::FeaturePython', obj_name)

fpo = box(obj)
box(obj)

return fpo
return obj
}}
}}


'''La méthode {{incode|create()}} se décompose comme suit :'''


{|class="wikitable" cellpadding="5px" width="100%"
<div class="mw-translate-fuzzy">
|style="width:25%" | {{incode|import FreeCAD as App}}
'''La méthode breakdown <code>create()</code>'''
|style="width:75%" | Importation standard pour la plupart des scripts Python, l'alias d'application n'est pas requis.
{|class="wikitable" cellpadding="5" style="float:right; margin-left: 15px; margin-right: 5px"
|style="width:30%" | <code>import FreeCAD as App</code> || Importation standard pour la plupart des scripts python. L'alias '''App''' n'est pas requis.
|-
|-
| {{incode|obj <nowiki>=</nowiki> ... addObject(...)}}
|<code>obj = ... addObject(...)</code> || Crée un nouvel objet FreeCAD FeaturePython avec le nom transmis à la méthode. S'il n'y a pas de conflit de noms, ce sera l'étiquette et le nom de l'objet créé, c'est-à-dire ce qui est visible dans l'arbre du modèle. Sinon, un nom et une étiquette uniques seront créés sur la base de 'nom_obj'.
| Crée un nouvel objet FeaturePython de FreeCAD avec le nom transmis à la méthode. S'il n'y a pas de conflit de nom, ce sera le libellé et le nom de l'objet créé. Sinon, un nom et une étiquette uniques seront créés en fonction de 'obj_name'.
|-
|-
| {{incode|box(obj)}}
|<code>fpo = box(obj)</code> || Créez l'instance de classe personnalisée et liez-la à l'objet FeaturePython.
| Crée notre instance de classe personnalisée.
|-
| {{incode|return obj}}
| Renvoie l'objet FeaturePython.
|}
|}
</div>


<div class="mw-translate-fuzzy">
La méthode <code>create()</code> n'est pas requise mais elle fournit un bon moyen d'encapsuler le code de création d'objet.
</div>


La méthode {{incode|create()}} n'est pas requise mais elle fournit un bon moyen d'encapsuler le code de création d'objet.


[[#top|En haut]]
-----


<span id="Testing_the_code"></span>
=== Test du code ===
=== Test du code ===


Nous pouvons maintenant tester notre nouvel objet. Enregistrez votre code et revenez à FreeCAD. Assurez-vous que vous avez ouvert un nouveau document, vous pouvez le faire en appuyant sur {{KEY|Ctrl}}+{{KEY|N}} ou en sélectionnant {{MenuCommand|Fichier → Nouveau}}.
<div class="mw-translate-fuzzy">
Maintenant, nous pouvons essayer notre nouvel objet. Enregistrez votre code et revenez à FreeCAD, assurez-vous d'avoir '''ouvert un nouveau document'''. Vous pouvez le faire en appuyant sur '''CTRL+n''' ou en sélectionnant '''Fichier -> Nouveau'''
</div>


Dans la console Python, tapez ce qui suit:
Dans la console Python, tapez ce qui suit :


{{Code|code=
{{Code|code=
>>> from fpo.box import box
from fpo.box import box
}}
}}


Maintenant, nous devons créer notre objet :
<div class="mw-translate-fuzzy">
<br>Maintenant, nous devons créer notre objet:
</div>


{{Code|code=
{{Code|code=
>>> box.create('my_box')
mybox = box.create('my_box')
}}
}}


[[Image:Fpo_treeview.png|right]]
<div class="mw-translate-fuzzy">
Vous devriez voir apparaître un nouvel objet dans la [[Tree_view/fr|Vue en arborescence]] étiqueté "my_box".
[[File:Fpo_treeview.png | right | 192px]]
Vous devriez voir un nouvel objet apparaître dans l'arborescence en haut à gauche intitulé '''my_box'''.<br><br>Notez que l'icône est grise. FreeCAD nous dit simplement que l'objet n'est pas en mesure d'afficher quoi que ce soit dans la vue 3D... pour l'instant. Cliquez sur l'objet et notez ce qui apparaît dans le panneau de propriétés en dessous. <br>Il n'y a pas grand-chose juste le nom de l'objet. Nous devrons ajouter quelques propriétés sous peu.
<br clear="all">
Rendons également le référencement de notre nouvel objet un peu plus pratique:
</div>


Notez que l'icône est grise. FreeCAD nous dit que l'objet ne peut rien afficher dans la [[3D_view/fr|Vue 3D]]. Cliquez sur l'objet et regardez ses propriétés dans l'[[Property_editor/fr|Éditeur de propriétés]]. Il n'y a pas grand-chose là-bas, juste le nom de l'objet.

Notez également qu'il y a une petite coche bleue à côté de l'objet FeaturePython dans l'arborescence. En effet, lorsqu'un objet est créé ou modifié, il est "touché" et doit être recalculé. Appuyez sur le bouton {{Button|[[Image:Std_Refresh.svg|16px]] [[Std_Refresh/fr|Std Rafraîchir]]}} pour y parvenir. Nous ajouterons du code pour automatiser cela plus tard.
{{Clear}}

Jetons un oeil aux attributs de notre objet :
{{Code|code=
{{Code|code=
dir(mybox)
>>> mybox = App.ActiveDocument.my_box
}}
}}


Cela retournera :
Et puis nous devrions jeter un oeil aux attributs de notre objet:

{{Code|code=
{{Code|code=
['Content', 'Document', 'ExpressionEngine', 'FullName', 'ID', 'InList',
>>> dir(mybox)
...
['Content', 'Document', 'ExpressionEngine', 'InList', 'InListRecursive', 'Label', 'MemSize', 'Module', 'Name', 'OutList', 'OutListRecursive', 'PropertiesList', 'Proxy', 'State', 'TypeId', 'ViewObject', '__class__',
'setPropertyStatus', 'supportedProperties', 'touch']
...
'setEditorMode', 'setExpression', 'supportedProperties', 'touch']
}}
}}


Il y a beaucoup d'attributs car nous accédons à l'objet FeaturePyton natif de FreeCAD créé à la première ligne de notre méthode {{incode|create()}}. La propriété {{incode|Proxy}} que nous avons ajoutée dans notre méthode {{incode|__init__()}} est là aussi.


Inspectons-la avec la méthode {{incode|dir()}} :
Il y a beaucoup d'attributs parce que nous accédons à l'objet FreeCAD FeaturePyton natif que nous avons créé dans la première ligne de notre {{incode|create()}} <div class="mw-translate-fuzzy">
méthode.
La propriété <code>Proxy</code> que nous avons ajoutée dans notre méthode <code>__init__()</code> est également là.
</div>


Inspectons cela en appelant le {{incode|dir()}}sur l'objet Proxy:
{{Code|code=
{{Code|code=
>>> dir(mybox.Proxy)
dir(mybox.Proxy)
['Object', 'Type', '__class__', '__delattr__', '__dict__', '__dir__',
...
'__str__', '__subclasshook__', '__weakref__']
}}
}}


Cela retournera :


{{Code|code=
Une fois que nous avons inspecté la propriété Proxy, nous pouvons voir notre {{incode|Object}} et {{incode|Type}} <div class="mw-translate-fuzzy">
['Type', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__',
propriétés. Cela signifie que nous accédons à l'objet Python personnalisé défini dans '''box.py'''.
...
</div>
'__str__', '__subclasshook__', '__weakref__']
}}

Nous pouvons voir notre propriété {{incode|Type}}. Vérifions :


<div class="mw-translate-fuzzy">
Appelez la propriété <code>Type</code> et regardez le résultat:
</div>
{{Code|code=
{{Code|code=
>>> mybox.Proxy.Type
mybox.Proxy.Type
'box'
}}
}}


Cela retournera :
Bien sûr, il retourne la valeur que nous avons assignée, donc nous savons que nous accédons à la classe personnalisée elle-même par le biais de l'objet FeaturePython.


De même, nous pouvons accéder à l'objet FreeCAD (pas à notre objet Python) en utilisant le{{incode|Object}}méthode:
{{Code|code=
{{Code|code=
'box'
>>> mybox.Proxy.Object
}}
}}


Il s'agit bien de la valeur assignée, nous savons donc que nous accédons à la classe personnalisée via l'objet FeaturePython.
C'était amusant! Mais voyons maintenant si nous pouvons rendre notre classe un peu plus intéressante ... et peut-être plus utile.


Voyons maintenant si nous pouvons rendre notre classe un peu plus intéressante, et peut-être aussi plus utile.


[[#top|En haut]]
-----


<span id="Adding_properties"></span>
=== Ajout de propriétés ===
===Ajout de propriétés===


Les propriétés sont l'élément vital d'une classe FeaturePython. Heureusement, FreeCAD supporte [[FeaturePython_Custom_Properties/fr|un certain nombre de types de propriétés]] pour les classes FeaturePython. Ces propriétés sont attachées directement à l'objet FeaturePython et sont entièrement sérialisées lors de l'enregistrement du fichier. Pour éviter d'avoir à sérialiser les données vous-même, il est conseillé de n'utiliser que ces types de propriétés.
<div class="mw-translate-fuzzy">
Les propriétés sont l'élément vital d'une classe FeaturePython.
<br><br> Heureusement, FreeCAD prend en charge [[FeaturePython_Custom_Properties/fr|un certain nombre de types de propriétés personnalisées de FeaturePython]] pour les classes FeaturePython. Ces propriétés sont attachées directement à l'objet FeaturePython lui-même et entièrement sérialisées lorsque le fichier est enregistré. Cela signifie que, sauf si vous souhaitez sérialiser les données vous-même, vous devrez trouver un moyen de les ancrer dans un type de propriété pris en charge.
<br><br> L'ajout de propriétés se fait tout simplement en utilisant le
</div>


L'ajout de propriétés se fait à l'aide de la méthode {{incode|add_property()}}. La syntaxe de cette méthode est la suivante :
Fortunately, FreeCAD supports [[FeaturePython_Custom_Properties|a number of property types]] for FeaturePython classes. These properties are attached directly to the FeaturePython object itself and fully serialized when the file is saved. That means, unless you want to serialize the data yourself, you'll need to find some way to wrangle it into a supported property type.


<!--Ne pas utiliser de modèle de code pour éviter la mise en évidence de la syntaxe-->
Adding properties is done quite simply using the {{incode|add_property()}} méthode. La syntaxe de la méthode est:
add_property(type, name, section, description)

Vous pouvez consulter la liste des propriétés prises en charge en tapant :


{{Code|code=
{{Code|code=
mybox.supportedProperties()
{{incode|add_property(type, name, section, description)}}
}}
}}


Essayons d'ajouter une propriété à notre classe de boîte. Passez à votre éditeur de code, passez à la méthode {{incode|__init__()}}, et à la fin de la méthode, ajoutez :
<div class="mw-translate-fuzzy">
{|class="wikitable" cellpadding="5" style="float:right; margin-left: 15px; margin-right: 5px; text-align:left"
!Tip
|-
||Vous pouvez afficher la liste des propriétés prises en charge pour un objet en tapant:<br><code>>>> mybox.supportedProperties()</code>
|}
<br>Essayons d'ajouter une propriété à notre classe box.
<br><br>Basculez vers votre éditeur de code et passez à la
</div> {{incode|__init__()}} méthode.

{{clear}}


<div class="mw-translate-fuzzy">
<br clear="all">Ensuite, à la fin de la méthode, ajoutez:
</div>
{{Code|code=
{{Code|code=
obj.addProperty('App::PropertyString', 'Description', 'Base', 'Box description').Description = ""
obj.addProperty('App::PropertyString', 'Description', 'Base', 'Box description').Description = ""
}}
}}

Notez comment nous utilisons la référence à l'objet FeaturePython (sérialisable), {{incode|obj}} <span class="mw-translate-fuzzy">et non l'instance de classe Python (non sérialisable),</span> {{incode|self}}<br>Quoi qu'il en soit, une fois que vous avez terminé, enregistrez les modifications et revenez à FreeCAD.
Notez que nous utilisons la référence à l'objet FeaturePython (sérialisable) {{incode|obj}}, et non l'instance de classe Python (non sérialisable) {{incode|self}}.
<br><br>Avant de pouvoir observer les modifications que nous avons apportées à notre code, nous devons recharger le module. Cela peut être accompli en redémarrant FreeCAD, mais le redémarrage de FreeCAD chaque fois que nous apportons une modification au code de classe python peut devenir un peu gênant. Pour le rendre plus facile, essayez ce qui suit dans la console Python:

Une fois que vous avez terminé, enregistrez les modifications et revenez à FreeCAD. Avant de pouvoir observer les modifications apportées à notre code, nous devons recharger le module. Cela peut être accompli en redémarrant FreeCAD, mais redémarrer FreeCAD à chaque fois que nous éditons le code serait gênant. Pour faciliter les choses, tapez ce qui suit dans la console Python :

{{Code|code=
{{Code|code=
>>> from importlib import reload
from importlib import reload
>>> reload(box)
reload(box)
}}
}}
<div class="mw-translate-fuzzy">
Cela rechargera le module box, incorporant les modifications que vous avez apportées au fichier '''box.py''' comme si vous aviez redémarré FreeCAD.
<br><br>Le module étant rechargé, voyons maintenant ce que nous obtenons lorsque nous créons un objet:
</div>
{{Code|code=
>>> box.create('box_property_test')}}
[[File:fpo_properties.png | right | 320px]]<div class="mw-translate-fuzzy">
Vous devriez voir le nouvel objet boîte apparaître dans l'arborescence à gauche.<br><br>
*Sélectionnez-le et regardez le panneau des propriétés. Là, vous devriez voir la propriété 'Description'.<br>
*Passez la souris sur le nom de la propriété à gauche et voyez l'infobulle apparaître avec le texte de description que vous avez fourni.<br>
*Sélectionnez le champ et saisissez ce que vous voulez. Vous remarquerez que les commandes de mise à jour Python sont exécutées et affichées dans la console lorsque vous tapez des lettres et que la propriété change.
<br><br>Mais avant de quitter le sujet des propriétés pour le moment, revenons en arrière et ajoutons quelques propriétés qui rendraient un objet boîte personnalisé *vraiment* utile: à savoir ''length'', ''width'' et ''height''.
<br><br>Revenez à votre code source et ajoutez les propriétés suivantes à
</div>


Avec le module rechargé, voyons ce que nous obtenons lorsque nous créons un objet :
*Select it and look at the [[Property editor]]. There, you should see the 'Description' property.
*Hover over the property name at left and see the tooltip appear with the description text you provided.
*Select the field and type whatever you like. You'll notice that Python update commands are executed and displayed in the console as you type letters and the property changes.


But before we leave the topic of properties for the moment, let's go back and add some properties that would make a custom box object *really* useful: namely, ''length'', ''width'', and ''height''. Return to your source code and add the following properties:
{{Code|code=
{{Code|code=
box.create('box_property_test')
__init__():
}}


Vous devriez voir le nouvel objet boîte apparaître dans l'arborescence :
obj.addProperty('App::PropertyLength', 'Length', 'Dimensions', 'Box length').Length = 10.0
*Sélectionnez-le et regardez l'éditeur de propriétés. Là, vous devriez voir la propriété ''Description''.
obj.addProperty('App::PropertyLength', 'Width', 'Dimensions', 'Box width').Width = '10 mm'
*Passez la souris sur le nom de la propriété à gauche et l'info-bulle devrait apparaître avec la description que vous avez fournie.
obj.addProperty('App::PropertyLength', 'Height', 'Dimensions', 'Box height').Height = '1 cm'
*Sélectionnez le champ et tapez ce que vous voulez. Vous remarquerez que les commandes de mise à jour Python sont exécutées et affichées dans la console lorsque vous tapez des lettres et que les propriétés changent.

[[#top|En haut]]

Ajoutons quelques propriétés supplémentaires. Retournez à votre code source et ajoutez les propriétés suivantes à la méthode {{incode|__init__()}} :

{{Code|code=
obj.addProperty('App::PropertyLength', 'Length', 'Dimensions', 'Box length').Length = 10.0
obj.addProperty('App::PropertyLength', 'Width', 'Dimensions', 'Box width').Width = '10 mm'
obj.addProperty('App::PropertyLength', 'Height', 'Dimensions', 'Box height').Height = '1 cm'
}}
}}

[[File:object_recompute_icon.png | left | 64px]]<div class="mw-translate-fuzzy">
Et ajoutons aussi un code pour recalculer le document automatiquement. Ajoutez la ligne suivante au-dessus de l'instruction {{incode|return()}} de la méthode {{incode|create()}}:
Une dernière chose: avez-vous remarqué comment la coche bleue apparaît à côté de l'objet FeaturePython dans l'arborescence à gauche?
En effet, lorsqu'un objet est créé ou modifié, il est "touché" et doit être recalculé. Cliquer sur les flèches "recycler" (les deux flèches formant un cercle) accomplira cela.
<br><br>Mais nous pouvons accomplir cela automatiquement en ajoutant la ligne suivante à la fin du
</div> {{incode|create()}} méthode:


{{Code|code=
{{Code|code=
App.ActiveDocument.recompute()
App.ActiveDocument.recompute()
}}
}}
<div class="mw-translate-fuzzy">
{|class="wikitable" cellpadding="5" style="margin-left: 15px; margin-right: 15px; text-align:left"
!Remarque
|-
|Soyez prudent lorsque vous recalculez un objet FeaturePython! En règle générale, vous ne devez pas essayer de recalculer un objet de l'intérieur de lui-même. Le recalcul des documents doit plutôt être géré par une méthode externe à l'objet, si possible.
|}
<br>Maintenant, testez vos modifications comme suit:<br>
*Enregistrez vos modifications et revenez à FreeCAD.<br>
*Supprimez tous les objets existants et rechargez votre module.<br>
*Enfin, créez un autre objet boîte à partir de la ligne de commande en appelant
</div> {{incode|>>> box.create('myBox')}}
[[File:fpo_box_properties.png | right | 320px]]
Once the box is created (and you've checked to make sure it's been recomputed!), select the object and look at your properties. You should note two things:


'''Faites attention à l'endroit où vous recalculez un objet FeaturePython. Le recalcul doit être effectué par une méthode externe à sa classe.'''
*Three new properties (''length'', ''width'', and ''height'')
*A new property group, ''Dimensions''.


[[Image:fpo_box_properties.png | right]]
Note also how the properties have dimensions. Specifically, they take on the linear dimension of the units set in the user preferences ({{MenuCommand|Edit → Preference... → Units tab}}).{{clear}}<br>In fact, if you were paying attention when you were entering the code, you will have noticed that three separate values were entered for each dimension. The length was a floating-point value (10.0), the width was a string, specifying millimeters ('10 mm') and the height was a string specifying centimeters ('1 cm'). Yet, the property rendered all three values the same way: 10 mm. Specifically, a floating-point value is assumed to be in the current document units, and the string values are parsed according to the units specified, then converted to document units.


Maintenant, testez vos modifications comme suit:
The nice thing about the {{incode|App::PropertyLength}} type is that it's a 'unit' type - values are understood as having specific units. Therefore, whenever you create a property that uses linear dimensions, use {{incode|App::PropertyLength}} comme type de propriété.
* Enregistrez vos modifications et rechargez votre module.
* Supprimez tous les objets dans l'arborescence.
* Créez un nouvel objet boîte à partir de la console Python en appelant {{incode|box.create('myBox')}}.


Une fois que la boîte est créée et que vous avez vérifié pour vous assurer qu'elle a été recalculée, sélectionnez l'objet et regardez ses propriétés. Vous devez noter deux choses:
* Un nouveau groupe de propriétés: ''Dimensions''.
* Trois nouvelles propriétés: ''Height'', ''Length'' et ''Width''.


Notez également que les propriétés ont des unités. Plus précisément, elles ont repris les unités linéaires définies dans les préférences de l'utilisateur ({{MenuCommand|Edition → Préférences... → Général → Unités}}).
-----
{{Clear}}


Vous avez sans doute remarqué que trois valeurs différentes ont été saisies pour les dimensions : une valeur en virgule flottante ({{incode|10.0}}) et deux chaînes de caractères différentes ({{incode|'10 mm'}} et {{incode|'1 cm'}}). Le type {{incode|App::PropertyLength}} suppose que les valeurs en virgule flottante sont en millimètres, les valeurs des chaînes sont analysées en fonction des unités spécifiées et, dans l'interface graphique, toutes les valeurs sont converties dans les unités spécifiées dans les préférences de l'utilisateur ({{incode|mm}} dans l'image). Ce comportement intégré rend le type {{incode|App::PropertyLength}} idéal pour les dimensions.

[[#top|En haut]]

<span id="Trapping_events"></span>
=== Piège à événements ===
=== Piège à événements ===


Le dernier élément requis pour un objet FeaturePython de base est le recouvrement d'événements. Un objet FeaturePython peut réagir aux événements avec des fonctions de rappel. Dans notre cas, nous voulons que l'objet réagisse chaque fois qu'il est recalculé. En d'autres termes, nous voulons intercepter les recalculs. Pour ce faire, nous devons ajouter une fonction avec un nom spécifique, {{incode|execute()}}, à la classe d'objets. Il existe plusieurs autres événements qui peuvent être piégés, à la fois dans l'objet FeaturePython lui-même et dans le [[Viewprovider/fr|ViewProvider]], que nous aborderons dans la [[Create_a_FeaturePython_object_part_II/fr|Création d'une boîte FeaturePython, partie II]].
<div class="mw-translate-fuzzy">

Le dernier élément requis pour un objet FeaturePython de base est le piégeage des événements. Plus précisément, nous devons piéger l'événement <code>execute()</code>, qui est appelé lorsque l'objet est recalculé. Il y a plusieurs autres événements au niveau du document qui peuvent être piégés dans notre objet, à la fois dans l'objet FeaturePython lui-même et dans le ViewProvider, que nous couvrirons dans une autre section.
Pour une référence complète des méthodes disponibles à implémenter sur les classes FeautrePython, voir [[FeaturePython_methods/fr|Méthodes FeaturePython]].
<br>

Ajoutez ce qui suit après la fonction <code>__init__()</code>:
Ajoutez ce qui suit après la fonction {{incode|__init__()}}:
</div>


Add the following after the {{incode|__init__()}} function:
{{Code|code=
{{Code|code=
def execute(self, obj):
def execute(self, obj):
"""
"""
Called on document recompute
Called on document recompute
"""
"""
print('Recomputing {0:s} ({1:s})'.format(obj.Name, self.Type))
}}


print('Recomputing {0:s} ({1:s})'.format(obj.Name, self.Type))
<div class="mw-translate-fuzzy">
}}
Testez le code comme suit:
*Enregistrez les modifications et rechargez le module box dans la console python FreeCAD.
*Supprimer tous les objets dans l'arborescence.
*Recréez l'objet boîte.
</div>

<div class="mw-translate-fuzzy">
Vous devriez voir le résultat dans la console Python, grâce à l'appel <code>recompute()</code> que nous avons ajouté à la méthode <code>create()</code>.
</div>

Bien sûr, la méthode <code>execute()</code> ne fait rien ici (sauf nous dire qu'elle a été appelée), mais c'est la clé de la magie des objets FeaturePython.


Testez le code en suivant à nouveau ces étapes:
<div class="mw-translate-fuzzy">
*Enregistrez et rechargez le module.
<br>'''Et voilà!'''
*Supprimer tous les objets.
<br>Vous savez maintenant comment construire un objet FeaturePython basique et fonctionnel!
*Créez un nouvel objet boîte.
</div>


Vous devriez voir la sortie imprimée dans la console Python, grâce à l'appel {{incode|recompute()}} que nous avons ajouté à la méthode {{incode|create()}}. Bien sûr, la méthode {{incode|execute()}} ne fait rien ici, sauf nous dire qu'elle a été appelée, mais elle est la clé de la magie des objets FeaturePython.
You now know how to build a basic, functional FeaturePython object!


Voilà, vous savez maintenant comment construire un objet FeaturePython basique et fonctionnel !


[[#top|En haut]]
-----


<span id="Complete_code"></span>
=== Le code terminé ===
=== Le code terminé ===

{{Code|code=
{{Code|code=
import FreeCAD as App
import FreeCAD as App

def create(obj_name):
def create(obj_name):
"""
"""
Object creation method
Object creation method
"""
"""

obj = App.ActiveDocument.addObject('App::FeaturePython', obj_name))
obj = App.ActiveDocument.addObject('App::FeaturePython', obj_name)

fpo = box(obj)
box(obj)

App.ActiveDocument.recompute()

return obj
return obj

class box():
class box():

def __init__(self, obj):
def __init__(self, obj):
"""
"""
Default Constructor
Default constructor
"""
"""

self.Type = 'box'
self.Type = 'box'

obj.addProperty('App::PropertyString', 'Description', 'Base', 'Box description').Description = ""
obj.addProperty('App::PropertyLength', 'Length', 'Dimensions', 'Box length').Length = 10.0
obj.addProperty('App::PropertyLength', 'Width', 'Dimensions', 'Box width').Width = '10 mm'
obj.addProperty('App::PropertyLength', 'Height', 'Dimensions', 'Box height').Height = '1 cm'
obj.Proxy = self
obj.Proxy = self

obj.addProperty('App::PropertyString', 'Description', 'Base', 'Box description').Description = ""
obj.addProperty('App::PropertyLength', 'Length', 'Dimensions', 'Box length').Length = 10.0
obj.addProperty('App::PropertyLength', 'Width', 'Dimensions', 'Box width').Width = '10 mm'
obj.addProperty('App::PropertyLength', 'Height', 'Dimensions', 'Box height').Height = '1 cm'

def execute(self, obj):
def execute(self, obj):
"""
"""
Called on document recompute
Called on document recompute
"""
"""

print('Recomputing {0:s} {1:s}'.format(obj.Name, self.Type))
print('Recomputing {0:s} ({1:s})'.format(obj.Name, self.Type))
}}
}}

<div class="mw-translate-fuzzy">
[[#top|En haut]]
{{docnav/fr

{{Docnav/fr
|[[PySide/fr|PySide]]
|[[PySide/fr|PySide]]
|[[Creating a FeaturePython Box, Part II/fr|Création d'un Box FeaturePython, Part II]]
|[[Create_a_FeaturePython_object_part_II/fr|Créer un objet FeaturePython partie II]]
}}
}}
</div>



{{Userdocnavi{{#translation:}}}}
[[Category:Poweruser Documentation{{#translation:}}]]
{{Powerdocnavi{{#translation:}}}}
[[Category:Developer Documentation{{#translation:}}]]
[[Category:Python Code{{#translation:}}]]
[[Category:Python Code{{#translation:}}]]
{{clear}}

Latest revision as of 09:47, 18 February 2023

Other languages:

Introduction

Les objets FeaturePython (également appelés Objets créés par script) offrent aux utilisateurs la possibilité d'étendre FreeCAD avec des objets qui s'intègrent de manière transparente dans le framework FreeCAD.

Cela favorise:

  • Le prototypage rapide de nouveaux objets et outils avec des classes personnalisées de Python.
  • Sauvegarde et restauration des données (également appelées sérialisation) via des objets App::Property sans intégrer de script dans le fichier de document FreeCAD.
  • Une liberté créative pour adapter FreeCAD à n'importe quelle tâche.

Sur cette page, nous allons construire un exemple de travail d'une classe personnalisée FeaturePython, en identifiant tous les composants principaux et en comprenant comment tout fonctionne au fur et à mesure.

Comment ça marche?

FreeCAD est livré avec un certain nombre de types d'objets par défaut pour gérer différents types de géométrie. Certains d'entre eux ont des alternatives "FeaturePython" qui permettent une personnalisation avec une classe Python définie par l'utilisateur.

Cette classe Python personnalisée prend une référence à l'un de ces objets et le modifie. Par exemple, la classe Python peut ajouter des propriétés à l'objet ou le lier à d'autres objets. De plus, la classe Python peut implémenter certaines méthodes pour permettre à l'objet de répondre aux événements du document, ce qui permet de piéger les modifications de propriété de l'objet et de recalculer le document.

Lorsque vous travaillez avec des classes personnalisées et des objets FeaturePython, il est important de savoir que la classe personnalisée et son état ne sont pas enregistrés dans le document car cela nécessiterait l'incorporation d'un script dans un fichier de document FreeCAD, ce qui poserait un risque de sécurité important. Seul l'objet FeaturePython lui-même est enregistré (sérialisé). Mais comme le chemin du module de script est stocké dans le document, un utilisateur n'a qu'à installer le code de classe Python personnalisé en tant que module importable, suivant la même structure de dossier, pour retrouver la fonctionnalité perdue.

En haut

Mise en place

Les classes d'objets FeaturePython doivent agir comme des modules importables dans FreeCAD. Cela signifie que vous devez les placer dans un chemin qui existe dans votre environnement Python (ou l'ajouter spécifiquement). Pour les besoins de ce tutoriel, nous allons utiliser le dossier Macro utilisateur FreeCAD, mais si vous avez une autre idée en tête, n'hésitez pas à l'utiliser à la place!

Si vous ne savez pas où se trouve le dossier des Macro de FreeCAD, tapez FreeCAD.getUserMacroDir(True) dans la console Python de FreeCAD :

  • Sous Linux, il s'agit généralement de /home/<username>/.local/share/FreeCAD/Mod/ (version 0.20 et suivantes) ou /home/<username>/.FreeCAD/Mod/ (version 0.19 et précédentes).
  • Sous Windows, c'est %APPDATA%\FreeCAD\Macro\, généralement C:\Users\<username>\Appdata\Roaming\FreeCAD\Macro\.
  • Sous macOS, il s'agit généralement de /Users/<username>/Library/Application Support/FreeCAD/Macro/.

Maintenant, nous devons créer des fichiers :

  • Dans le dossier Macro, créez un nouveau dossier appelé fpo.
  • Dans le dossier fpo, créez un fichier vide : __init__.py.
  • Dans le dossier fpo, créez un nouveau dossier appelé box.
  • Dans le dossier box, créez deux fichiers : __init__.py et box.py (laissez les deux cases vides pour l'instant).

La structure de votre dossier devrait ressembler à ceci :

Macro/
    |--> fpo/
        |--> __init__.py
        |--> box/
            |--> __init__.py
            |--> box.py

Le dossier fpo est l'endroit pour jouer avec les nouveaux objets FeaturePython et le dossier box est le module dans lequel nous allons travailler. __init__.py indique à Python qu'il y a un module importable dans le dossier et box.py sera le fichier de classe pour notre nouvel objet FeaturePython.

Une fois nos chemins et fichiers de module créés, nous assurons que FreeCAD est correctement configuré :

Enfin, naviguez jusqu'au dossier Macro/fpo/box et ouvrez box.py dans votre éditeur de code préféré. Nous ne modifierons que ce fichier.

En haut

Un objet FeaturePython

Commençons par écrire notre classe et son constructeur :

class box():

    def __init__(self, obj):
        """
        Default constructor
        """

        self.Type = 'box'

        obj.Proxy = self

La méthode __init__() se décompose comme suit:

def __init__(self, obj): Les paramètres font référence à la classe Python elle-même et à l'objet FeaturePython auquel elle est attachée.
self.Type = 'box' Définition de chaîne du type Python personnalisé.
obj.Proxy = self Stocke une référence à l'instance Python dans l'objet FeaturePython.

Ajoutez le code suivant en haut du fichier :

import FreeCAD as App

def create(obj_name):
    """
    Object creation method
    """

    obj = App.ActiveDocument.addObject('App::FeaturePython', obj_name)

    box(obj)

    return obj

La méthode create() se décompose comme suit :

import FreeCAD as App Importation standard pour la plupart des scripts Python, l'alias d'application n'est pas requis.
obj = ... addObject(...) Crée un nouvel objet FeaturePython de FreeCAD avec le nom transmis à la méthode. S'il n'y a pas de conflit de nom, ce sera le libellé et le nom de l'objet créé. Sinon, un nom et une étiquette uniques seront créés en fonction de 'obj_name'.
box(obj) Crée notre instance de classe personnalisée.
return obj Renvoie l'objet FeaturePython.

La méthode create() n'est pas requise mais elle fournit un bon moyen d'encapsuler le code de création d'objet.

En haut

Test du code

Nous pouvons maintenant tester notre nouvel objet. Enregistrez votre code et revenez à FreeCAD. Assurez-vous que vous avez ouvert un nouveau document, vous pouvez le faire en appuyant sur Ctrl+N ou en sélectionnant Fichier → Nouveau.

Dans la console Python, tapez ce qui suit :

from fpo.box import box

Maintenant, nous devons créer notre objet :

mybox = box.create('my_box')

Vous devriez voir apparaître un nouvel objet dans la Vue en arborescence étiqueté "my_box".

Notez que l'icône est grise. FreeCAD nous dit que l'objet ne peut rien afficher dans la Vue 3D. Cliquez sur l'objet et regardez ses propriétés dans l'Éditeur de propriétés. Il n'y a pas grand-chose là-bas, juste le nom de l'objet.

Notez également qu'il y a une petite coche bleue à côté de l'objet FeaturePython dans l'arborescence. En effet, lorsqu'un objet est créé ou modifié, il est "touché" et doit être recalculé. Appuyez sur le bouton Std Rafraîchir pour y parvenir. Nous ajouterons du code pour automatiser cela plus tard.

Jetons un oeil aux attributs de notre objet :

dir(mybox)

Cela retournera :

['Content', 'Document', 'ExpressionEngine', 'FullName', 'ID', 'InList',
...
'setPropertyStatus', 'supportedProperties', 'touch']

Il y a beaucoup d'attributs car nous accédons à l'objet FeaturePyton natif de FreeCAD créé à la première ligne de notre méthode create(). La propriété Proxy que nous avons ajoutée dans notre méthode __init__() est là aussi.

Inspectons-la avec la méthode dir() :

dir(mybox.Proxy)

Cela retournera :

['Type', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__',
...
'__str__', '__subclasshook__', '__weakref__']

Nous pouvons voir notre propriété Type. Vérifions :

mybox.Proxy.Type

Cela retournera :

'box'

Il s'agit bien de la valeur assignée, nous savons donc que nous accédons à la classe personnalisée via l'objet FeaturePython.

Voyons maintenant si nous pouvons rendre notre classe un peu plus intéressante, et peut-être aussi plus utile.

En haut

Ajout de propriétés

Les propriétés sont l'élément vital d'une classe FeaturePython. Heureusement, FreeCAD supporte un certain nombre de types de propriétés pour les classes FeaturePython. Ces propriétés sont attachées directement à l'objet FeaturePython et sont entièrement sérialisées lors de l'enregistrement du fichier. Pour éviter d'avoir à sérialiser les données vous-même, il est conseillé de n'utiliser que ces types de propriétés.

L'ajout de propriétés se fait à l'aide de la méthode add_property(). La syntaxe de cette méthode est la suivante :

add_property(type, name, section, description)

Vous pouvez consulter la liste des propriétés prises en charge en tapant :

mybox.supportedProperties()

Essayons d'ajouter une propriété à notre classe de boîte. Passez à votre éditeur de code, passez à la méthode __init__(), et à la fin de la méthode, ajoutez :

obj.addProperty('App::PropertyString', 'Description', 'Base', 'Box description').Description = ""

Notez que nous utilisons la référence à l'objet FeaturePython (sérialisable) obj, et non l'instance de classe Python (non sérialisable) self.

Une fois que vous avez terminé, enregistrez les modifications et revenez à FreeCAD. Avant de pouvoir observer les modifications apportées à notre code, nous devons recharger le module. Cela peut être accompli en redémarrant FreeCAD, mais redémarrer FreeCAD à chaque fois que nous éditons le code serait gênant. Pour faciliter les choses, tapez ce qui suit dans la console Python :

from importlib import reload
reload(box)

Avec le module rechargé, voyons ce que nous obtenons lorsque nous créons un objet :

box.create('box_property_test')

Vous devriez voir le nouvel objet boîte apparaître dans l'arborescence :

  • Sélectionnez-le et regardez l'éditeur de propriétés. Là, vous devriez voir la propriété Description.
  • Passez la souris sur le nom de la propriété à gauche et l'info-bulle devrait apparaître avec la description que vous avez fournie.
  • Sélectionnez le champ et tapez ce que vous voulez. Vous remarquerez que les commandes de mise à jour Python sont exécutées et affichées dans la console lorsque vous tapez des lettres et que les propriétés changent.

En haut

Ajoutons quelques propriétés supplémentaires. Retournez à votre code source et ajoutez les propriétés suivantes à la méthode __init__() :

obj.addProperty('App::PropertyLength', 'Length', 'Dimensions', 'Box length').Length = 10.0
obj.addProperty('App::PropertyLength', 'Width', 'Dimensions', 'Box width').Width = '10 mm'
obj.addProperty('App::PropertyLength', 'Height', 'Dimensions', 'Box height').Height = '1 cm'

Et ajoutons aussi un code pour recalculer le document automatiquement. Ajoutez la ligne suivante au-dessus de l'instruction return() de la méthode create():

App.ActiveDocument.recompute()

Faites attention à l'endroit où vous recalculez un objet FeaturePython. Le recalcul doit être effectué par une méthode externe à sa classe.

Maintenant, testez vos modifications comme suit:

  • Enregistrez vos modifications et rechargez votre module.
  • Supprimez tous les objets dans l'arborescence.
  • Créez un nouvel objet boîte à partir de la console Python en appelant box.create('myBox').

Une fois que la boîte est créée et que vous avez vérifié pour vous assurer qu'elle a été recalculée, sélectionnez l'objet et regardez ses propriétés. Vous devez noter deux choses:

  • Un nouveau groupe de propriétés: Dimensions.
  • Trois nouvelles propriétés: Height, Length et Width.

Notez également que les propriétés ont des unités. Plus précisément, elles ont repris les unités linéaires définies dans les préférences de l'utilisateur (Edition → Préférences... → Général → Unités).

Vous avez sans doute remarqué que trois valeurs différentes ont été saisies pour les dimensions : une valeur en virgule flottante (10.0) et deux chaînes de caractères différentes ('10 mm' et '1 cm'). Le type App::PropertyLength suppose que les valeurs en virgule flottante sont en millimètres, les valeurs des chaînes sont analysées en fonction des unités spécifiées et, dans l'interface graphique, toutes les valeurs sont converties dans les unités spécifiées dans les préférences de l'utilisateur (mm dans l'image). Ce comportement intégré rend le type App::PropertyLength idéal pour les dimensions.

En haut

Piège à événements

Le dernier élément requis pour un objet FeaturePython de base est le recouvrement d'événements. Un objet FeaturePython peut réagir aux événements avec des fonctions de rappel. Dans notre cas, nous voulons que l'objet réagisse chaque fois qu'il est recalculé. En d'autres termes, nous voulons intercepter les recalculs. Pour ce faire, nous devons ajouter une fonction avec un nom spécifique, execute(), à la classe d'objets. Il existe plusieurs autres événements qui peuvent être piégés, à la fois dans l'objet FeaturePython lui-même et dans le ViewProvider, que nous aborderons dans la Création d'une boîte FeaturePython, partie II.

Pour une référence complète des méthodes disponibles à implémenter sur les classes FeautrePython, voir Méthodes FeaturePython.

Ajoutez ce qui suit après la fonction __init__():

def execute(self, obj):
    """
    Called on document recompute
    """

    print('Recomputing {0:s} ({1:s})'.format(obj.Name, self.Type))

Testez le code en suivant à nouveau ces étapes:

  • Enregistrez et rechargez le module.
  • Supprimer tous les objets.
  • Créez un nouvel objet boîte.

Vous devriez voir la sortie imprimée dans la console Python, grâce à l'appel recompute() que nous avons ajouté à la méthode create(). Bien sûr, la méthode execute() ne fait rien ici, sauf nous dire qu'elle a été appelée, mais elle est la clé de la magie des objets FeaturePython.

Voilà, vous savez maintenant comment construire un objet FeaturePython basique et fonctionnel !

En haut

Le code terminé

import FreeCAD as App

def create(obj_name):
    """
    Object creation method
    """

    obj = App.ActiveDocument.addObject('App::FeaturePython', obj_name)

    box(obj)

    App.ActiveDocument.recompute()

    return obj

class box():

    def __init__(self, obj):
        """
        Default constructor
        """

        self.Type = 'box'

        obj.Proxy = self

        obj.addProperty('App::PropertyString', 'Description', 'Base', 'Box description').Description = ""
        obj.addProperty('App::PropertyLength', 'Length', 'Dimensions', 'Box length').Length = 10.0
        obj.addProperty('App::PropertyLength', 'Width', 'Dimensions', 'Box width').Width = '10 mm'
        obj.addProperty('App::PropertyLength', 'Height', 'Dimensions', 'Box height').Height = '1 cm'

    def execute(self, obj):
        """
        Called on document recompute
        """

        print('Recomputing {0:s} ({1:s})'.format(obj.Name, self.Type))

En haut