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

From FreeCAD Documentation
No edit summary
No edit summary
Line 171: Line 171:
}}
}}


Cela retournera:
This will return:


{{Code|code=
{{Code|code=
Line 179: Line 179:
}}
}}


Nous pouvons voir notre propriété {{incode|Type}}. Vérifions:
<div class="mw-translate-fuzzy">
Une fois que nous avons inspecté la propriété Proxy, nous pouvons voir notre
</div>


{{Code|code=
{{Code|code=

Revision as of 21:07, 13 January 2021

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 Macro de FreeCAD, tapez FreeCAD.getUserMacroDir(True) dans la console Python de FreeCAD :

  • Sous Linux, il s'agit généralement de /home/<username>/.FreeCAD/Macro/.
  • Sous Windows, c'est %APPDATA%\FreeCAD\Macro\, ce qui est généralement C:\Users\<username>\Appdata\Roaming\FreeCAD\Macro\.
  • Sous Mac OSX, il s'agit généralement de /Users/<username>/Library/Preferences/FreeCAD/Macro/.

Maintenant, nous devons créer des fichiers.

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 FreeCAD FeaturePython 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

This will return:

'box'

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.

C'était amusant! Mais voyons maintenant si nous pouvons rendre notre classe un peu plus intéressante ... et peut-être plus utile.

top

Ajout de propriétés

Les propriétés sont l'élément vital d'une classe FeaturePython.

Heureusement, FreeCAD prend en charge 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.

L'ajout de propriétés se fait tout simplement en utilisant le

Adding properties is done using the add_property() method. The syntax for the method is:

add_property(type, name, section, description)
Tip
Vous pouvez afficher la liste des propriétés prises en charge pour un objet en tapant:
>>> mybox.supportedProperties()


Essayons d'ajouter une propriété à notre classe box.

Basculez vers votre éditeur de code et passez à la

mybox.supportedProperties()


Ensuite, à la fin de la méthode, ajoutez:

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

Notez comment nous utilisons la référence à l'objet FeaturePython (sérialisable),


Quoi qu'il en soit, une fois que vous avez terminé, enregistrez les modifications et revenez à FreeCAD.

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:

from importlib import reload
reload(box)

Cela rechargera le module box, incorporant les modifications que vous avez apportées au fichier box.py comme si vous aviez redémarré FreeCAD.

Le module étant rechargé, voyons maintenant 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 à gauche.

  • Sélectionnez-le et regardez le panneau des propriétés. Là, vous devriez voir la propriété 'Description'.
  • 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.
  • 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.



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.

Revenez à votre code source et ajoutez les propriétés suivantes à

top

Let's add some more properties. Return to your source code and add the following properties to the __init__() method:

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'

And let's also add some code to recompute the document automatically. Add the following line above the return() statement in the create() method :

App.ActiveDocument.recompute()
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.


Maintenant, testez vos modifications comme suit:

  • Enregistrez vos modifications et revenez à FreeCAD.
  • Supprimez tous les objets existants et rechargez votre module.
  • Enfin, créez un autre objet boîte à partir de la ligne de commande en appelant

Now, test your changes as follows:

  • Save your changes and reload your module.
  • Delete all objects in the Tree view.
  • Create a new box object from the Python console by calling box.create('myBox').

Once the box is created and you've checked to make sure it has been recomputed, select the object and look at its properties. You should note two things:

  • A new property group: Dimensions.
  • Three new properties: Height, Length and Width.

Note also how the properties have units. More specifically, they have taken on the linear units set in the user preferences (Edit → Preference... → General → Units).

No doubt you noticed that three different values were entered for the dimensions: a floating-point value (10.0) and two different strings ('10 mm' and '1 cm'). The App::PropertyLength type assumes floating-point values are in millimeters, string values are parsed according to the units specified, and in the GUI all values are converted to the units specified in the user preferences (mm in the image). This built-in behavior makes the App::PropertyLength type ideal for dimensions.

top

Piège à événements

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 execute(), 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.
Ajoutez ce qui suit après la fonction __init__():

For a complete reference of methods available to implement on FeautrePython classes, see FeaturePython methods.

Add the following after the __init__() function:

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

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

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.

Vous devriez voir le résultat dans la console Python, grâce à l'appel recompute() que nous avons ajouté à la méthode create().

That's it, you now know how to build a basic, functional FeaturePython object!

top

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))

top