📘 Cours : Création d’add-ons pour FreeCAD
Objectif de la leçon : créer une fenêtre avec des champs pour saisir la longueur, la largeur et la hauteur, et construire une boîte avec ces paramètres en cliquant sur un bouton.
🖼 Partie 1. Comment fonctionne la GUI dans FreeCAD ?
FreeCAD utilise PySide — un wrapper Python sur la bibliothèque Qt (la même que dans Blender, Maya et de nombreux autres programmes).
Composants principaux :
QtGui.QDialog— fenêtre modaleQtGui.QLineEdit— champ de saisie de texteQtGui.QPushButton— boutonQtGui.QFormLayout— disposition pratique « étiquette + champ »
💡 Tous les éléments de la GUI sont créés à l’intérieur du script Python, sans fichiers externes (bien que l’on puisse utiliser
.uide Qt Designer — mais nous commencerons par le plus simple).
🛠 Partie 2. Add-on : « Box Builder avec GUI »
Nous allons étendre l’add-on précédent en ajoutant une boîte de dialogue.
Étape 1. Créez un dossier
.../Mod/BoxBuilderAddon/
Étape 2. Fichier InitGui.py
# InitGui.py
import FreeCADGui
from BoxBuilderAddon.box_builder_workbench import BoxBuilderWorkbench
FreeCADGui.addWorkbench(BoxBuilderWorkbench())
Étape 3. Fichier box_builder_workbench.py
# box_builder_workbench.py
import FreeCAD, FreeCADGui
from PySide import QtGui, QtCore
# === FONCTION DE CRÉATION DE BOÎTE ===
def create_box(length, width, height, name="CustomBox"):
doc = FreeCAD.ActiveDocument
if not doc:
doc = FreeCAD.newDocument("BoxBuilder")
# Nom unique
base_name = name
index = 1
obj_name = base_name
while obj_name in [obj.Name for obj in doc.Objects]:
obj_name = f"{base_name}_{index}"
index += 1
box = doc.addObject("Part::Box", obj_name)
box.Length = length
box.Width = width
box.Height = height
doc.recompute()
return box
# === FENÊTRE DE DIALOGUE ===
class BoxBuilderDialog(QtGui.QDialog):
def __init__(self):
super(BoxBuilderDialog, self).__init__()
self.setWindowTitle("Box Builder")
self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
self.resize(300, 150)
# Champs de saisie
self.length_input = QtGui.QLineEdit("30.0")
self.width_input = QtGui.QLineEdit("20.0")
self.height_input = QtGui.QLineEdit("10.0")
# Boutons
self.create_button = QtGui.QPushButton("Create Box")
self.cancel_button = QtGui.QPushButton("Cancel")
# Connexion des boutons
self.create_button.clicked.connect(self.on_create)
self.cancel_button.clicked.connect(self.reject)
# Disposition
layout = QtGui.QFormLayout()
layout.addRow("Length (mm):", self.length_input)
layout.addRow("Width (mm):", self.width_input)
layout.addRow("Height (mm):", self.height_input)
button_layout = QtGui.QHBoxLayout()
button_layout.addWidget(self.create_button)
button_layout.addWidget(self.cancel_button)
main_layout = QtGui.QVBoxLayout()
main_layout.addLayout(layout)
main_layout.addLayout(button_layout)
self.setLayout(main_layout)
def on_create(self):
try:
length = float(self.length_input.text())
width = float(self.width_input.text())
height = float(self.height_input.text())
if length <= 0 or width <= 0 or height <= 0:
raise ValueError("All dimensions must be positive")
create_box(length, width, height)
self.accept() # Fermer la fenêtre
except ValueError as e:
QtGui.QMessageBox.warning(self, "Input Error", f"Invalid input:\n{str(e)}")
# === COMMANDE ===
class BoxBuilderCommand:
def GetResources(self):
return {
"MenuText": "Box Builder",
"ToolTip": "Create a box with custom dimensions"
}
def Activated(self):
dialog = BoxBuilderDialog()
dialog.exec_() # Appel modal
def IsActive(self):
return True
# === ENVIRONNEMENT DE TRAVAIL ===
class BoxBuilderWorkbench(FreeCADGui.Workbench):
MenuText = "Box Builder"
ToolTip = "Create custom boxes with GUI"
def Initialize(self):
self.list = ["BoxBuilderCommand"]
self.appendToolbar("Box Tools", self.list)
self.appendMenu("Box Builder", self.list)
def GetClassName(self):
return "Gui::PythonWorkbench"
FreeCADGui.addCommand("BoxBuilderCommand", BoxBuilderCommand())
🔍 Analyse des parties clés
1. Fenêtre de dialogue (BoxBuilderDialog)
- Hérite de
QtGui.QDialog - Utilise
QFormLayoutpour un placement soigné des champs - Le bouton Create Box appelle
on_create(), Cancel — ferme la fenêtre
2. Traitement de la saisie
- Convertit le texte en
float - Vérifie que les valeurs sont positives
- En cas d’erreur — affiche un avertissement via
QMessageBox.warning
3. Création de l’objet
- La fonction
create_box()est séparée — pour un code plus propre - Génère un nom unique pour éviter les conflits
4. Lancement de la fenêtre
dialog.exec_()— rend la fenêtre modale (vous ne pouvez pas interagir avec FreeCAD tant qu’elle est ouverte)
▶️ Étape 4. Vérification du fonctionnement
- Enregistrez les fichiers
- Redémarrez FreeCAD
- Sélectionnez l’environnement de travail « Box Builder »
- Cliquez sur le bouton « Box Builder »
- Dans la fenêtre qui apparaît, saisissez les dimensions → cliquez sur Create Box
✅ Une boîte avec vos paramètres devrait apparaître !
Essayez :
- De saisir des lettres → une erreur apparaîtra
- De saisir un nombre négatif → erreur
- De saisir des nombres décimaux (par exemple,
12.5) → cela fonctionne !
🧪 Exercice pratique
- Ajoutez un quatrième champ : « Name » — pour que l’utilisateur puisse définir le nom de l’objet.
- Faites en sorte que si le nom est vide, la valeur par défaut (
"CustomBox") soit utilisée. - Ajoutez une case à cocher « Center on origin » — si elle est activée, la boîte doit être centrée à l’origine.
💡 Indice pour le centrage :
Après avoir créé la boîte, modifiez sa propriétéPlacement:from FreeCAD import Vector box.Placement.Base = Vector(-length/2, -width/2, -height/2)
💡 Conseils pour travailler avec la GUI
- Enveloppez toujours la saisie dans
try/except— l’utilisateur peut saisir n’importe quoi - Utilisez
QDoubleValidatorpour n’autoriser que les nombres (facultatif) - Pour les interfaces complexes, il est préférable d’utiliser Qt Designer et de charger des fichiers
.ui, mais pour les tâches simples — le code est plus facile
▶️ Et ensuite ?
Dans la Leçon 5, nous allons :
- Apprendre à enregistrer les paramètres entre les démarrages de FreeCAD
- Faire en sorte que la dernière valeur de dimension saisie soit mémorisée
- Utiliser le mécanisme intégré de FreeCAD :
FreeCAD.ParamGet()
Cela rendra votre add-on encore plus pratique !