📘 Samouczek: Tworzenie dodatków dla FreeCAD
Cel lekcji: Sprawić, by dodatek „Box Builder” zapamiętywał ostatnio wprowadzone wymiary i przywracał je przy następnym uruchomieniu.
💾 Część 1. Jak FreeCAD przechowuje ustawienia?
FreeCAD zapewnia wbudowany mechanizm do przechowywania parametrów użytkownika — za pośrednictwem Menedżera parametrów.
Działa on z hierarchiczną bazą danych parametrów, podobną do rejestru systemu Windows.
Główne metody:
# Pobierz grupę parametrów
params = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/MyAddon")
# Zapisz wartość
params.SetFloat("LastLength", 30.0)
params.SetString("LastName", "MyBox")
# Załaduj wartość (z wartością domyślną)
length = params.GetFloat("LastLength", 10.0) # 10.0 — jeśli taki parametr nie istnieje
name = params.GetString("LastName", "DefaultBox")
`
💡 Wskazówka: Ścieżka „User parameter:BaseApp/Preferences/…” jest standardową lokalizacją dla ustawień użytkownika.
`
🛠 Część 2. Zaktualizowany dodatek: „Box Builder z Pamięcią”
Zmodyfikujemy poprzedni dodatek, dodając zapisywanie i ładowanie ostatnich wartości.
Plik box_builder_workbench.py (zaktualizowana wersja)
# box_builder_workbench.py
import FreeCAD, FreeCADGui
from PySide import QtGui, QtCore
# === ŚCIEŻKA DO USTAWIEŃ ===
PARAM_PATH = "User parameter:BaseApp/Preferences/BoxBuilderAddon"
def get_saved_settings():
"""Ładuje zapisane ustawienia lub zwraca wartości domyślne"""
params = FreeCAD.ParamGet(PARAM_PATH)
return {
"length": params.GetFloat("LastLength", 30.0),
"width": params.GetFloat("LastWidth", 20.0),
"height": params.GetFloat("LastHeight", 10.0),
"name": params.GetString("LastName", "CustomBox")
}
def save_settings(length, width, height, name):
"""Zapisuje bieżące ustawienia"""
params = FreeCAD.ParamGet(PARAM_PATH)
params.SetFloat("LastLength", length)
params.SetFloat("LastWidth", width)
params.SetFloat("LastHeight", height)
params.SetString("LastName", name)
# === FUNKCJA TWORZENIA PUDEŁKA ===
def create_box(length, width, height, name="CustomBox"):
doc = FreeCAD.ActiveDocument
if not doc:
doc = FreeCAD.newDocument("BoxBuilder")
# Unikalna nazwa
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
# === OKNO DIALOGOWE ===
class BoxBuilderDialog(QtGui.QDialog):
def __init__(self):
super(BoxBuilderDialog, self).__init__()
self.setWindowTitle("Box Builder")
self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
self.resize(300, 180)
# Załaduj zapisane ustawienia
settings = get_saved_settings()
# Pola wprowadzania
self.length_input = QtGui.QLineEdit(str(settings["length"]))
self.width_input = QtGui.QLineEdit(str(settings["width"]))
self.height_input = QtGui.QLineEdit(str(settings["height"]))
self.name_input = QtGui.QLineEdit(settings["name"])
# Przyciski
self.create_button = QtGui.QPushButton("Create Box")
self.cancel_button = QtGui.QPushButton("Cancel")
# Połączenie
self.create_button.clicked.connect(self.on_create)
self.cancel_button.clicked.connect(self.reject)
# Układ
layout = QtGui.QFormLayout()
layout.addRow("Nazwa:", self.name_input)
layout.addRow("Długość (mm):", self.length_input)
layout.addRow("Szerokość (mm):", self.width_input)
layout.addRow("Wysokość (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:
name = self.name_input.text().strip()
if not name:
name = "CustomBox"
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("Wszystkie wymiary muszą być dodatnie")
# Stwórz obiekt
create_box(length, width, height, name)
# Zapisz ustawienia
save_settings(length, width, height, name)
self.accept()
except ValueError as e:
QtGui.QMessageBox.warning(self, "Błąd wejścia", f"Nieprawidłowe wejście:\n{str(e)}")
# === KOMENDA I ŚRODOWISKO ROBOCZE (niezmienione) ===
class BoxBuilderCommand:
def GetResources(self):
return {"MenuText": "Box Builder", "ToolTip": "Utwórz pudełko z niestandardowymi wymiarami"}
def Activated(self):
dialog = BoxBuilderDialog()
dialog.exec_()
def IsActive(self):
return True
class BoxBuilderWorkbench(FreeCADGui.Workbench):
MenuText = "Box Builder"
ToolTip = "Utwórz niestandardowe pudełka za pomocą GUI"
def Initialize(self):
self.list = ["BoxBuilderCommand"]
self.appendToolbar("Narzędzia pudełka", self.list)
self.appendMenu("Box Builder", self.list)
def GetClassName(self):
return "Gui::PythonWorkbench"
FreeCADGui.addCommand("BoxBuilderCommand", BoxBuilderCommand())
`
🔍 Co się zmieniło?
Funkcje dodane:
get_saved_settings()— ładuje ostatnie wartościsave_settings()— zapisuje bieżące wartości
Ścieżka do parametrów:
PARAM_PATH = "User parameter:BaseApp/Preferences/BoxBuilderAddon"
→ Wszystkie ustawienia są przechowywane w oddzielnej grupie, bez kolizji z innymi dodatkami.
Pole na nazwę dodane do interfejsu.
- Gdy okno się uruchamia — pola są wypełniane zapisanymi wartościami.
- Po utworzeniu — bieżące wartości są zapisywane automatycznie.
`
▶️ Sprawdzanie działania
- Uruchom FreeCAD
- Otwórz Box Builder
- Wprowadź, na przykład:
- Nazwa: MyTestBox
- Długość: 50
- Szerokość: 30
- Wysokość: 20
- Kliknij Create Box
- Zamknij FreeCAD
- Uruchom ponownie
- Otwórz Box Builder
`
✅ Pola powinny być wypełnione tymi samymi wartościami!
`
📂 Gdzie są przechowywane te ustawienia?
- Windows: w rejestrze (
HKEY_CURRENT_USER\SOFTWARE\FreeCAD\...) - Linux/macOS: w pliku
user.cfgw folderze FreeCAD
Ale nie musisz tego wiedzieć — FreeCAD sam zarządza przechowywaniem.
`
🧪 Praktyczne zadanie
- Dodaj pole wyboru „Wyśrodkuj na początku” i zapisz jego stan między uruchomieniami.
- Upewnij się, że przy pierwszym uruchomieniu dodatku używane są rozsądne wartości domyślne (już zaimplementowane).
- Dodaj przycisk „Resetuj do ustawień domyślnych”, który resetuje pola do wartości domyślnych i czyści zapisane ustawienia.
Wskazówka do resetowania:
def reset_settings():
params = FreeCAD.ParamGet(PARAM_PATH)
params.RemGroup("BoxBuilderAddon") # Usuwa całą grupę
`
💡 Porady
- Zawsze określaj wartość domyślną w
GetFloat(),GetString()itp. - Nie zapisuj zbyt wiele — tylko to, czego użytkownik naprawdę potrzebuje.
- Używaj unikalnej ścieżki (
BoxBuilderAddon), aby uniknąć konfliktów z innymi dodatkami.
`
▶️ Co dalej?
W Lekcji 6 będziemy:
- Dodawać ikony do przycisków i środowiska roboczego
- Uczyć się, jak używać SVG i PNG w interfejsie
- Sprawić, by dodatek był atrakcyjny wizualnie