📘 Corso di formazione: Creazione di addon per FreeCAD
Obiettivo della lezione: creare una finestra con campi per l’inserimento di lunghezza, larghezza e altezza, e al clic di un pulsante costruire una scatola con questi parametri.
🖼 Parte 1. Come funziona la GUI in FreeCAD?
FreeCAD utilizza PySide — un wrapper Python per la libreria Qt (la stessa usata in Blender, Maya e molti altri programmi).
Componenti principali:
QtGui.QDialog— finestra modaleQtGui.QLineEdit— campo di input testualeQtGui.QPushButton— pulsanteQtGui.QFormLayout— layout comodo “etichetta + campo”
💡 Tutti gli elementi GUI vengono creati all’interno dello script Python, senza file esterni (anche se è possibile utilizzare
.uida Qt Designer — ma inizieremo con il semplice).
🛠 Parte 2. Addon: «Box Builder con GUI»
Estenderemo l’addon precedente, aggiungendo una finestra di dialogo.
Passaggio 1. Crea una cartella
.../Mod/BoxBuilderAddon/
Passaggio 2. File InitGui.py
# InitGui.py
import FreeCADGui
from BoxBuilderAddon.box_builder_workbench import BoxBuilderWorkbench
FreeCADGui.addWorkbench(BoxBuilderWorkbench())
Passaggio 3. File box_builder_workbench.py
# box_builder_workbench.py
import FreeCAD, FreeCADGui
from PySide import QtGui, QtCore
# === FUNZIONE DI CREAZIONE SCATOLA ===
def create_box(length, width, height, name="CustomBox"):
doc = FreeCAD.ActiveDocument
if not doc:
doc = FreeCAD.newDocument("BoxBuilder")
# Nome unico
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
# === FINESTRA DI DIALOGO ===
class BoxBuilderDialog(QtGui.QDialog):
def __init__(self):
super(BoxBuilderDialog, self).__init__()
self.setWindowTitle("Box Builder")
self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
self.resize(300, 150)
# Campi di input
self.length_input = QtGui.QLineEdit("30.0")
self.width_input = QtGui.QLineEdit("20.0")
self.height_input = QtGui.QLineEdit("10.0")
# Pulsanti
self.create_button = QtGui.QPushButton("Create Box")
self.cancel_button = QtGui.QPushButton("Cancel")
# Connessione dei pulsanti
self.create_button.clicked.connect(self.on_create)
self.cancel_button.clicked.connect(self.reject)
# Layout
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() # Chiudi la finestra
except ValueError as e:
QtGui.QMessageBox.warning(self, "Input Error", f"Invalid input:\n{str(e)}")
# === COMANDO ===
class BoxBuilderCommand:
def GetResources(self):
return {
"MenuText": "Box Builder",
"ToolTip": "Create a box with custom dimensions"
}
def Activated(self):
dialog = BoxBuilderDialog()
dialog.exec_() # Chiamata modale
def IsActive(self):
return True
# === AMBIENTE DI LAVORO ===
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())
🔍 Analisi delle parti chiave
1. Finestra di dialogo (BoxBuilderDialog)
- Eredita da
QtGui.QDialog - Utilizza
QFormLayoutper un posizionamento ordinato dei campi - Il pulsante Create Box chiama
on_create(), Cancel — chiude la finestra
2. Elaborazione dell’input
- Convertiamo il testo in
float - Verifichiamo che i valori siano positivi
- In caso di errore — mostriamo un avviso tramite
QMessageBox.warning
3. Creazione dell’oggetto
- La funzione
create_box()è separata — per un codice più pulito - Genera un nome unico per evitare conflitti
4. Avvio della finestra
dialog.exec_()— rende la finestra modale (non è possibile interagire con FreeCAD finché è aperta)
▶️ Passaggio 4. Verifica del funzionamento
- Salva i file
- Riavvia FreeCAD
- Seleziona l’ambiente di lavoro «Box Builder»
- Clicca sul pulsante «Box Builder»
- Nella finestra che appare, inserisci le dimensioni → clicca su Create Box
✅ Dovrebbe apparire una scatola con i tuoi parametri!
Prova a:
- Inserire lettere → apparirà un errore
- Inserire un numero negativo → errore
- Inserire numeri decimali (ad esempio,
12.5) → funziona!
🧪 Esercizio pratico
- Aggiungi un quarto campo: «Name» — in modo che l’utente possa specificare il nome dell’oggetto.
- Fai in modo che, se il nome è vuoto, venga utilizzato un valore predefinito (
"CustomBox"). - Aggiungi una casella di controllo «Center on origin» — se selezionata, la scatola dovrebbe essere centrata all’origine.
💡 Suggerimento per la centratura:
Dopo aver creato la scatola, modifica la sua proprietàPlacement:from FreeCAD import Vector box.Placement.Base = Vector(-length/2, -width/2, -height/2)
💡 Consigli per lavorare con la GUI
- Avvolgi sempre l’input in
try/except— l’utente può inserire qualsiasi cosa - Utilizza
QDoubleValidatorper consentire solo numeri (opzionale) - Per interfacce complesse è meglio usare Qt Designer e caricare file
.ui, ma per compiti semplici — il codice è più facile
▶️ Cosa c’è dopo?
Nella Lezione 5 impareremo a:
- Salvare le impostazioni tra gli avvii di FreeCAD
- Fare in modo che l’ultimo valore delle dimensioni inserito venga memorizzato
- Utilizzare il meccanismo integrato di FreeCAD:
FreeCAD.ParamGet()
Questo renderà il tuo addon ancora più comodo!