Obiekty tworzone skryptami, zapis atrybutów
Wprowadzenie
Obiekty tworzone skryptami są odbudowywane przy każdym otwarciu dokumentu FCStd. W tym celu dokument przechowuje referencję do modułu i klasy Python, które zostały użyte do stworzenia obiektu, wraz z jego właściwościami.
Atrybuty klasy użytej do utworzenia obiektu mogą być również zapisywane, czyli "serializowane". Może to być dalej kontrolowane przez metody klasy dumps i loads.
Zapisywanie wszystkich atrybutów
Domyślnie, atrybuty zapisane w klasie obiektu są atrybutami ze słownika __dict__ klasy.
# various_states.py
class VariousStates:
def __init__(self, obj):
obj.addProperty("App::PropertyLength", "Length")
obj.addProperty("App::PropertyArea", "Area")
obj.Length = 15
obj.Area = 300
obj.Proxy = self
Type = dict()
Type["Version"] = "Custom"
Type["Release"] = "production"
self.Type = Type
self.Type = "Custom"
self.ver = "0.18"
self.color = (0, 0, 1)
self.width = 2.5
def execute(self, obj):
pass
Obiekt może zostać utworzony przy użyciu tej klasy i zapisany do pliku my_document.FCstd. Jeśli żaden konkretny dostawca widoku nie jest przypisany do nowego obiektu, jego klasa proxy jest po prostu ustawiana na wartość inną niż None, w tym przypadku na 1.
import FreeCAD as App
import various_states
doc = App.newDocument()
doc.FileName = "my_document.FCStd"
obj = doc.addObject("Part::FeaturePython", "Custom")
various_states.VariousStates(obj)
if App.GuiUp:
obj.ViewObject.Proxy = 1
doc.recompute()
doc.save()
Po ponownym otwarciu pliku możemy sprawdzić słownik klasy obiektu.
>>> obj = App.ActiveDocument.Custom
>>> print(obj.Proxy)
<various_states.VariousStates object at 0x7f0a899bde10>
>>> print(obj.Proxy.__dict__)
{'Type': {'Version': 'Custom', 'Release': 'production'}, 'ver': '0.18', 'color': [0, 0, 1], 'width': 2.5}
Widzimy, że wszystkie atrybuty zaczynające się od self w klasie zostały zapisane. Mogą one być różnych typów, w tym string, list, float i dictionary. Oryginalna krotka dla self.color została przekonwertowana na listę, ale poza tym wszystkie atrybuty zostały załadowane tak samo.
Zapisywanie określonych atrybutów
Możemy zdefiniować klasę podobną do pierwszej, która implementuje określone atrybuty do zapisania.
# various_states.py
class CustomStates:
def __init__(self, obj):
obj.addProperty("App::PropertyLength", "Length")
obj.addProperty("App::PropertyArea", "Area")
obj.Length = 15
obj.Area = 300
obj.Proxy = self
Type = dict()
Type["Version"] = "Custom"
Type["Release"] = "production"
self.Type = Type
self.ver = "0.18"
self.color = (0, 0, 1)
self.width = 2.5
def execute(self, obj):
pass
def dumps(self):
return self.color, self.width
def loads(self, state):
self.color = state[0]
self.width = state[1]
Wartością zwrotną dumps jest obiekt, który zostanie zserializowany. Może to być pojedyncza wartość lub krotka wartości. Po przywróceniu obiektu klasa wywołuje metodę loads, przekazując zmienną state z serializowaną zawartością. W tym przypadku state jest krotką, która jest rozpakowywana do odpowiednich zmiennych, aby zrekonstruować "stan", który istniał pierwotnie.
state = (self.color, self.width)
state = ((0, 0, 1), 2.5)
Możemy utworzyć obiekt z tą klasą i zapisać dokument, tak jak w poprzednim przykładzie. Po ponownym otwarciu pliku możemy sprawdzić słownik klasy obiektu.
>>> obj2 = App.ActiveDocument.Custom2
>>> print(obj2.Proxy)
<various_states.CustomStates object at 0x7fb399496630>
>>> print(obj2.Proxy.__dict__)
{'color': [0, 0, 1], 'width': 2.5}
Oryginalna krotka dla self.color została przekonwertowana na listę, ale poza tym informacje zostały odzyskane prawidłowo. Zamiast przywracania wszystkich atrybutów, jak w poprzednim przypadku, przywrócone zostały tylko atrybuty określone w dumps i loads.
Użycie
Identyfikacja typu
Zwykle obiekty tworzone skryptami powinny używać właściwości do przechowywania informacji, ponieważ są one automatycznie przywracane po otwarciu dokumentu.
Czasami jednak klasa przechowuje wewnętrzne informacje, które nie są przeznaczone do modyfikacji, ale które są pomocne w inspekcji.
Na przykład, większość obiektów środowiska pracy Rysunek Roboczy ustawia atrybut Type, który może być użyty do określenia typu używanego obiektu.
class DraftObject:
def __init__(self, obj, _type):
self.Type = _type
def dumps(self):
return self.Type
def loads(self, state):
if state:
self.Type = state
Wszystkie obiekty mają właściwość TypeId, ale dla obiektów tworzonych skryptami ta właściwość nie jest użyteczna, ponieważ zawsze odnosi się do nadrzędnej klasy C++, na przykład Part::Part2DObjectPython lub Part::FeaturePython. Dlatego posiadanie tego dodatkowego atrybutu Proxy.Type w klasie jest przydatne do traktowania każdego obiektu w określony sposób.
Migracja obiektu
Informacje o wersji mogą być przechowywane wewnątrz klasy w celu weryfikacji pochodzenia obiektu.
class CustomObject:
def __init__(self, obj, _type):
self.Type = _type
self.version = "0.18"
def dumps(self):
return self.Type, self.version
def loads(self, state):
if state:
self.Type = state[0]
self.version = state[1]
Jeśli struktura klasy ulegnie zmianie, tzn. zmienią się jej właściwości lub metody, zostanie zmieniona ich nazwa lub zostaną usunięte, możemy przetestować atrybut version w celu migracji starszego obiektu do nowego zestawu właściwości lub do nowej klasy. Można to zrobić implementując metodę onDocumentRestored, jak wyjaśniono na stronie Obiekty tworzone skryptami, migracja.
class CustomObject:
def onDocumentRestored(self, obj):
if hasattr(obj.Proxy, "version") and obj.Proxy.version:
if obj.Proxy.version == "0.18":
self.migrate_from_018(obj)
def migrate_from_018(self, obj):
...
Odnośniki internetowe
- Obiekty tworzone skryptami
- Migracja obiektów tworzonych skryptami
- Dyskusja na forum FreeCAD: Serializacja obiektów tworzonych skryptami: json czy pickle?
- obj.Proxy.Type jest typu dict, a nie string, wyjaśnienie
dumpsiloadsna forum. - Moduł Pickle w dokumentacji Python.
- Tworzenie skryptów FreeCAD: Python, Wprowadzenie do środowiska Python, Poradnik: Tworzenie skryptów Python, Podstawy tworzenia skryptów FreeCAD
- Moduły: Moduły wbudowane, Jednostki miar, Ilość
- Środowiska pracy: Tworzenie Środowiska pracy, Polecenia Gui, Polecenia, Instalacja większej liczby Środowisk pracy
- Siatki i elementy: Skrytpy w Środowisku Siatek, v, Konwerska Mesh na Part, PythonOCC
- Obiekty parametryczne: Obiekty tworzone skryptami, Obsługa obrazu (Ikonka niestandardowa w widoku drzewa)
- Scenegraph: Coin (Inventor) scenegraph, Pivy
- Interfejs graficzny: Stworzenie interfejsu, Kompletne stworzenie interfejsu w środowisku Python (1, 2, 3, 4, 5), PySide, PySide examples początkujący, średniozaawansowany, zaawansowany
- Makrodefinicje: Makrodefinicje, Instalacja makrodefinicji
- Osadzanie programu: Osadzanie programu FreeCAD, Osadzanie GUI FreeCAD
- Pozostałe: Wyrażenia, Wycinki kodu, Funkcja kreślenia linii, Biblioteka matematyczna FreeCAD dla wektorów (deprecated)
- Węzły użytkowników: Centrum użytkownika, Centrum Power użytkowników, Centrum programisty