13.1.13. Inställningseditorn#

Många kameraapplikationer behöver en handfull inställningar som en icke-programmerare kan ändra – ett tröskelvärde, ett läge, ett Wi-Fi-lösenord – utan att röra skriptet. OpenMV Cam Settings Editor är IDE:ns verktyg för det: en JSON-fil beskriver kontrollerna, editorn förvandlar den beskrivningen till ett formulär, och ditt skript läser tillbaka de sparade värdena med json.load(). Filen är både konfigurationen och definitionen av sin egen editor, så samma konfiguration som lagrar värdena lägger även ut det grafiska gränssnittet för att redigera dem.

Undermenyn Verktyg → OpenMV Cam Settings Editor innehåller dess tre åtgärder.

  • Open OpenMV Cam Settings Config File läser konfigurationen från den anslutna kamerans enhet och öppnar den i editorn; att spara skriver tillbaka den till kameran.

  • Open Config File gör detsamma för en .json-fil på din dator, för att förbereda en konfiguration offline.

  • Create Default Config skriver en startkonfiguration till disk och öppnar den – ett exempel som prövar varje kontrolltyp, redo att skalas ned till de inställningar din egen applikation behöver.

The OpenMV Cam Settings Editor showing the default demo configuration -- Camera, Processing, Network, and System tabs, with the Camera tab's exposure and gain sliders, resolution and pixel-format dropdowns, mirror and flip checkboxes, and a digital-zoom slider, above the Save and Cancel buttons

Inställningsredigeraren med standardkonfigurationen öppen – JSON-filens kontroller upplagda som ett formulär (flikar, skjutreglage, rullgardinsmenyer, kryssrutor), med Save och Cancel längst ned.#

13.1.13.1. En konfigurationsfils anatomi#

En konfigurationsfil är ett enda JSON-objekt med två nycklar:

  • title (string, valfritt) – redigerarfönstrets titel. Standard är OpenMV Cam Settings Editor.

  • controls (array, obligatorisk) – listan av kontrollobjekt som redigeraren renderar, i ordning, som rader i ett formulär. Detta är hela det grafiska gränssnittet.

{
  "title": "Camera Settings",
  "controls": [
    { "type": "slider", "name": "threshold", "label": "Threshold", "value": 50 },
    { "type": "checkbox", "name": "draw_overlays", "label": "Draw Overlays", "value": true }
  ]
}

Varje post i controls är en kontroll – ett textfält, ett tal, en kryssruta, en rullgardinsmeny, en skjutreglage, en grupp, en flikrad, en statisk etikett, och så vidare. Dess type väljer widgeten; resten av objektet konfigurerar den. Alla nycklar redigeraren inte känner igen lämnas orörda när filen sparas, så du kan behålla dina egna metadata i filen vid sidan av kontrollerna.

13.1.13.2. Nycklar som varje kontroll delar#

Varje kontrollobjekt accepterar dessa nycklar, oavsett dess type:

  • type (string, obligatorisk) – vilken widget som ska byggas, t.ex. "slider" eller "combobox". En saknad eller okänd type renderar en inaktiverad Unknown control-platshållare istället för att få hela filen att misslyckas, så ett stavfel kostar dig en kontroll, inte formuläret.

  • name (string) – en identifierare för ditt bruk. Redigeraren läser den aldrig; den bara bevarar den. Ge varje kontroll ett unikt name så använder ditt skript det för att hitta den kontrollens sparade värde.

  • label (string) – texten som visas bredvid eller på kontrollen. För de flesta kontroller är detta formaterad text – HTML-taggar och <a href>-länkar fungerar.

  • tooltip (string) – inforuta för kontrollen.

  • enabled (boolean, standard true) – sätt till false för att visa kontrollen nedtonad och skrivskyddad.

Behållarkontroller (group, tabs) använder title istället för label för sin rubrik, och tabs tar sin inforuta per flik; skillnaderna noteras på varje kontrolls sida.

13.1.13.3. Spara och läsa värden#

En kontroll som håller ett värde – en kryssruta, ett skjutreglage, ett textfält – bär det i en value-nyckel. När du klickar på Spara skriver redigeraren varje kontrolls aktuella value direkt tillbaka in i samma kontrollobjekt, på plats, och skriver om filen. Filen behåller sin struktur: inget flyttas, bara value-nycklarna ändras. Det finns ingen separat platt mappning från name till värde – värdena bor inuti kontrollerna, precis där de definieras.

Det är därför layouten spelar roll för ditt skript. Arrayerna controls och tabs behåller den ordning du byggde dem i, så filen kan inte indexeras efter namn som en dictionary – config["controls"]["threshold"] fungerar inte. Denna lilla hjälpfunktion överbryggar klyftan: ge den sökvägen av namn ned till värdet du vill ha, så vandrar den genom trädet åt dig.

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"]

Varje steg i sökvägen är en kontrolls name, eller en fliks title (en flik tar inget eget name, även om du får lägga till ett och det behålls). Flikraden och eventuell group du inte namngav är transparenta – find stegar genom dem – så du listar bara flikarna och kontrollerna du märkte, nära en kapslad config[...][...]-uppslagning. En namngiven group är ett eget steg, så find kan även returnera dess kryssrutevärde. Ge varje kontroll ett unikt name så att en sökväg aldrig blir tvetydig. Fullständigt exempel läser värden ur den kapslade demolayouten.

Eftersom konfigurationen är ren JSON beror inget i ditt skript på redigeraren – redigeraren skriver bara den fil ditt skript redan läser. En enhet kan bära sin konfiguration och ett användarvänligt sätt att ändra den medan skriptet förblir en enkel läsare av värden.

En kontrolltyp framtvingar sin inmatning vid Spara: en lineedit med en mask eller regex vägrar låta redigeraren spara medan dess text är ogiltig eller ofullständig, och namnger fälten som ska åtgärdas. Varje annan kontroll begränsar inmatning medan du redigerar – ett skjutreglage kan inte lämna sitt intervall, en spinbox klämmer till sina gränser – så en sparad fil är alltid giltig.

13.1.13.4. Referens för konfigurationsfil#

Kontrolltyperna dokumenteras på sidorna nedan, grupperade efter vad de gör.