13.1.13. Edytor ustawień#
Wiele aplikacji kamerowych potrzebuje kilku ustawień, które osoba nieprogramująca może zmienić – progu, trybu, hasła Wi-Fi – bez ruszania skryptu. OpenMV Cam Settings Editor to narzędzie IDE do tego celu: plik JSON opisuje kontrolki, edytor zamienia ten opis w formularz, a Twój skrypt odczytuje zapisane wartości z powrotem za pomocą json.load(). Plik jest zarówno konfiguracją, jak i definicją własnego edytora, więc ta sama konfiguracja, która przechowuje wartości, wyznacza również układ GUI do ich edycji.
Podmenu Tools → OpenMV Cam Settings Editor zawiera jego trzy akcje.
Open OpenMV Cam Settings Config File odczytuje konfigurację z dysku podłączonej kamery i otwiera ją w edytorze; zapisanie zapisuje ją z powrotem do kamery.
Open Config File robi to samo dla pliku
.jsonna Twoim komputerze, do przygotowania konfiguracji offline.Create Default Config zapisuje konfigurację startową na dysku i otwiera ją – przykład, który przećwicza każdy typ kontrolki, gotowy do ograniczenia do ustawień, których potrzebuje Twoja własna aplikacja.

Edytor ustawień z otwartą domyślną konfiguracją – elementy sterujące pliku JSON rozmieszczone w postaci formularza (karty, suwaki, listy rozwijane, pola wyboru), z przyciskami Save i Cancel na dole.#
13.1.13.1. Budowa pliku konfiguracyjnego#
Plik konfiguracyjny to pojedynczy obiekt JSON z dwoma kluczami:
title (string, opcjonalny) – tytuł okna edytora. Domyślnie
OpenMV Cam Settings Editor.controls (array, wymagany) – lista obiektów kontrolek, które edytor renderuje po kolei jako wiersze formularza. To cały interfejs graficzny.
{
"title": "Camera Settings",
"controls": [
{ "type": "slider", "name": "threshold", "label": "Threshold", "value": 50 },
{ "type": "checkbox", "name": "draw_overlays", "label": "Draw Overlays", "value": true }
]
}
Każdy wpis w controls to jedna kontrolka – pole tekstowe, liczba, pole wyboru, lista rozwijana, suwak, grupa, pasek zakładek, statyczna etykieta i tak dalej. Jego type wybiera widżet; reszta obiektu go konfiguruje. Wszelkie klucze, których edytor nie rozpoznaje, pozostają nietknięte podczas zapisywania pliku, więc możesz przechowywać w pliku własne metadane obok kontrolek.
13.1.13.3. Zapisywanie i odczytywanie wartości#
Kontrolka, która przechowuje wartość – pole wyboru, suwak, pole tekstowe – przechowuje ją w kluczu value. Gdy klikniesz Zapisz, edytor zapisuje bieżącą value każdej kontrolki z powrotem bezpośrednio do tego samego obiektu kontrolki, w miejscu, i przepisuje plik. Plik zachowuje swoją strukturę: nic się nie przesuwa, zmieniają się tylko klucze value. Nie ma osobnej płaskiej mapy name na wartość – wartości żyją wewnątrz kontrolek, dokładnie tam, gdzie są zdefiniowane.
Dlatego układ ma znaczenie dla Twojego skryptu. Tablice controls i tabs zachowują kolejność, w jakiej je zbudowałeś, więc pliku nie można indeksować po nazwie jak słownika – config["controls"]["threshold"] nie działa. Ta mała funkcja pomocnicza wypełnia tę lukę: podaj jej ścieżkę nazw aż do wartości, której szukasz, a ona przejdzie za Ciebie po drzewie.
import json
def find(node, *path):
"""Return the control at a path of names; read its value with
["value"]. The tab strip and any unnamed group are transparent,
so you list only the tabs and controls you gave a name."""
for key in path:
match = _child(node, key)
if match is None:
raise KeyError(key)
node = match
return node
def _child(node, key):
for member in node.get("controls", []) + node.get("tabs", []):
if member.get("name") == key or member.get("title") == key:
return member
if "name" not in member and ("controls" in member or "tabs" in member):
match = _child(member, key) # see through an unnamed group / the tab strip
if match is not None:
return match
return None
with open("config.json") as file:
config = json.load(file)
threshold = find(config, "threshold")["value"]
Każdy krok w ścieżce to name kontrolki lub title zakładki (zakładka nie przyjmuje własnego name, choć możesz go dodać i zostanie zachowany). Pasek zakładek oraz każda group, której nie nazwałeś, są przezroczyste – find przez nie przechodzi – więc wymieniasz tylko zakładki i kontrolki, którym nadałeś etykietę, blisko zagnieżdżonego odwołania config[...][...]. Nazwana group jest osobnym krokiem, więc find może też zwrócić wartość jej pola wyboru. Nadaj każdej kontrolce unikalny name, aby ścieżka nigdy nie była niejednoznaczna. Pełny przykład odczytuje wartości z zagnieżdżonego układu demonstracyjnego.
Ponieważ konfiguracja to zwykły JSON, nic w Twoim skrypcie nie zależy od edytora – edytor tylko zapisuje plik, który Twój skrypt i tak już odczytuje. Urządzenie może nosić swoją konfigurację i przyjazny sposób jej zmiany, podczas gdy skrypt pozostaje zwykłym czytelnikiem wartości.
Jeden typ kontrolki wymusza swoje dane wejściowe przy zapisie: lineedit z mask lub regex nie pozwala edytorowi zapisać, dopóki jego tekst jest nieprawidłowy lub niekompletny, i wskazuje pola do poprawienia. Każda inna kontrolka ogranicza dane wejściowe podczas edycji – suwak nie może opuścić swojego zakresu, spinbox przycina wartość do swoich granic – więc zapisany plik jest zawsze prawidłowy.
13.1.13.4. Dokumentacja pliku konfiguracyjnego#
Typy kontrolek są udokumentowane na poniższych stronach, pogrupowane według tego, co robią.