📘 Tutorial: Creating Addons for FreeCAD
Lesson Goal: Create a window with fields for entering length, width, and height, and build a box with these parameters by clicking a button.
In This Article
🖼 Part 1. How GUI works in FreeCAD?
FreeCAD uses PySide — a Python wrapper over the Qt library (the same one used in Blender, Maya, and many other programs).
Key components:
QtGui.QDialog— modal windowQtGui.QLineEdit— text input fieldQtGui.QPushButton— buttonQtGui.QFormLayout— convenient “label + field” layout
💡 All GUI elements are created within a Python script, without external files (although you can use
.uifrom Qt Designer — but we’ll start with something simple).
🛠 Part 2. Addon: “Box Builder with GUI”
We will extend the previous addon by adding a dialog box.
Step 1. Create a folder
.../Mod/BoxBuilderAddon/
Step 2. File InitGui.py
# InitGui.py
import FreeCADGui
from BoxBuilderAddon.box_builder_workbench import BoxBuilderWorkbench
FreeCADGui.addWorkbench(BoxBuilderWorkbench())
Step 3. File box_builder_workbench.py
# box_builder_workbench.py
import FreeCAD, FreeCADGui
from PySide import QtGui, QtCore
# === BOX CREATION FUNCTION ===
def create_box(length, width, height, name="CustomBox"):
doc = FreeCAD.ActiveDocument
if not doc:
doc = FreeCAD.newDocument("BoxBuilder")
# Unique name
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
# === DIALOG WINDOW ===
class BoxBuilderDialog(QtGui.QDialog):
def __init__(self):
super(BoxBuilderDialog, self).__init__()
self.setWindowTitle("Box Builder")
self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
self.resize(300, 150)
# Input fields
self.length_input = QtGui.QLineEdit("30.0")
self.width_input = QtGui.QLineEdit("20.0")
self.height_input = QtGui.QLineEdit("10.0")
# Buttons
self.create_button = QtGui.QPushButton("Create Box")
self.cancel_button = QtGui.QPushButton("Cancel")
# Connect buttons
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() # Close the window
except ValueError as e:
QtGui.QMessageBox.warning(self, "Input Error", f"Invalid input:\n{str(e)}")
# === COMMAND ===
class BoxBuilderCommand:
def GetResources(self):
return {
"MenuText": "Box Builder",
"ToolTip": "Create a box with custom dimensions"
}
def Activated(self):
dialog = BoxBuilderDialog()
dialog.exec_() # Modal call
def IsActive(self):
return True
# === WORKBENCH ===
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())
🔍 Breakdown of Key Parts
1. Dialog Window (BoxBuilderDialog)
- Inherits from
QtGui.QDialog - Uses
QFormLayoutfor neat field placement - The Create Box button calls
on_create(), Cancel — closes the window
2. Input Processing
- Convert text to
float - Check that values are positive
- In case of error — show a warning via
QMessageBox.warning
3. Object Creation
- The
create_box()function is separated — for cleaner code - Generates a unique name to avoid conflicts
4. Window Launch
dialog.exec_()— makes the window modal (you cannot interact with FreeCAD while it is open)
▶️ Step 4. Checking the Operation
- Save the files
- Restart FreeCAD
- Select the «Box Builder» workbench
- Click the «Box Builder» button
- In the window that appears, enter dimensions → click Create Box
✅ A box with your parameters should appear!
Try:
- Entering letters → an error will appear
- Entering a negative number → error
- Entering fractional numbers (e.g.,
12.5) → works!
🧪 Practical Task
- Add a fourth field: «Name» — so that the user can set the object’s name.
- Make sure that if the name is empty, the default value (
"CustomBox") is used. - Add a checkbox «Center on origin» — if enabled, the box should be centered at the origin.
💡 Hint for centering:
After creating the box, change itsPlacementproperty:from FreeCAD import Vector box.Placement.Base = Vector(-length/2, -width/2, -height/2)
💡 Tips for Working with GUI
- Always wrap input in
try/except— the user can enter anything - Use
QDoubleValidatorto allow only numbers (optional) - For complex interfaces, it’s better to use Qt Designer and load
.uifiles, but for simple tasks — the code is easier
▶️ What’s next?
In Lesson 5 we will:
- Learn how to save settings between FreeCAD launches
- Make sure the last entered dimension value is remembered
- Use FreeCAD’s built-in mechanism:
FreeCAD.ParamGet()
This will make your addon even more convenient!