13.1.13. Редактор налаштувань#

Багато застосунків для камери потребують кількох налаштувань, які непрограміст може змінити – поріг, режим, пароль Wi-Fi – не торкаючись скрипта. OpenMV Cam Settings Editor — це інструмент IDE для цього: файл JSON описує елементи керування, редактор перетворює цей опис на форму, а ваш скрипт зчитує збережені значення через json.load(). Файл є водночас конфігурацією та визначенням власного редактора, тож та сама конфігурація, що зберігає значення, також компонує GUI для їх редагування.

Підменю Tools → OpenMV Cam Settings Editor містить три його дії.

  • Open OpenMV Cam Settings Config File зчитує конфігурацію з диска підключеної камери та відкриває її в редакторі; збереження записує її назад на камеру.

  • Open Config File робить те саме для файлу .json на вашому комп’ютері, для підготовки конфігурації офлайн.

  • Create Default Config записує початкову конфігурацію на диск і відкриває її – приклад, що задіює всі типи елементів керування, готовий до скорочення до налаштувань, потрібних саме вашому застосунку.

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

Редактор налаштувань з відкритою типовою конфігурацією – елементи керування з файлу JSON, оформлені у вигляді форми (вкладки, повзунки, розкривні списки, прапорці), із кнопками Save і Cancel унизу.#

13.1.13.1. Будова файлу конфігурації#

Файл конфігурації – це єдиний об’єкт JSON із двома ключами:

  • title (рядок, необов’язковий) – заголовок вікна редактора. За замовчуванням OpenMV Cam Settings Editor.

  • controls (масив, обов’язковий) – список об’єктів елементів керування, які редактор відображає за порядком як рядки форми. Це весь графічний інтерфейс.

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

Кожен запис у controls – це один елемент керування: текстове поле, число, прапорець, розкривний список, повзунок, група, смуга вкладок, статичний підпис тощо. Його type обирає віджет; решта об’єкта його налаштовує. Будь-які ключі, які редактор не розпізнає, залишаються недоторканими під час збереження файлу, тож ви можете зберігати власні метадані у файлі поряд з елементами керування.

13.1.13.2. Ключі, спільні для всіх елементів керування#

Кожен об’єкт елемента керування приймає ці ключі незалежно від його type:

  • type (рядок, обов’язковий) – який віджет побудувати, наприклад "slider" або "combobox". Відсутній або нерозпізнаний type відображає вимкнений заповнювач Unknown control, а не спричиняє помилку всього файлу, тож помилка друку коштує вам одного елемента керування, а не форми.

  • name (рядок) – ідентифікатор для вашого використання. Редактор ніколи його не читає; він лише зберігає його. Надайте кожному елементу керування унікальне name, і ваш скрипт використає його, щоб знайти збережене значення цього елемента керування.

  • label (рядок) – текст, що відображається поруч з елементом керування або на ньому. Для більшості елементів керування це форматований текст – працюють HTML-теги та посилання <a href>.

  • tooltip (рядок) – підказка при наведенні для елемента керування.

  • enabled (булеве значення, за замовчуванням true) – встановіть false, щоб показати елемент керування сірим і доступним лише для читання.

Контейнерні елементи керування (group, tabs) використовують title замість label для свого заголовка, а tabs приймає підказку для кожної вкладки; відмінності зазначені на сторінці кожного елемента керування.

13.1.13.3. Збереження та зчитування значень#

Елемент керування, що зберігає значення – прапорець, повзунок, текстове поле – містить його в ключі value. Коли ви натискаєте Save, редактор записує поточне value кожного елемента керування безпосередньо назад у той самий об’єкт елемента керування, на місці, і перезаписує файл. Файл зберігає свою структуру: ніщо не переміщується, змінюються лише ключі value. Немає окремого плоского зіставлення name зі значенням – значення живуть усередині елементів керування, саме там, де вони визначені.

Ось чому компонування важливе для вашого скрипта. Масиви controls і tabs зберігають порядок, у якому ви їх побудували, тож файл не можна індексувати за іменем, як словник – config["controls"]["threshold"] не працює. Цей невеликий помічник долає цю перешкоду: передайте йому шлях імен аж до потрібного значення, і він пройде дерево за вас.

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

Кожен крок у шляху – це name елемента керування або title вкладки (вкладка не має власного name, хоча ви можете додати його, і воно зберігається). Смуга вкладок і будь-яка group, яку ви не назвали, є прозорими – find проходить крізь них – тож ви перелічуєте лише вкладки та елементи керування, яким дали підпис, майже як у вкладеному пошуку config[...][...]. Названа group є окремим кроком, тож find може також повернути значення її прапорця. Надайте кожному елементу керування унікальне name, щоб шлях ніколи не був неоднозначним. Повний приклад зчитує значення з вкладеного демонстраційного компонування.

Оскільки конфігурація – це звичайний JSON, ніщо у вашому скрипті не залежить від редактора – редактор лише записує файл, який ваш скрипт уже читає. Пристрій може нести свою конфігурацію та зручний спосіб її змінити, тоді як скрипт залишається простим зчитувачем значень.

Один тип елемента керування примусово перевіряє свій ввід під час Save: lineedit з mask або regex не дозволяє редактору зберегти, поки його текст недійсний або неповний, і називає поля, які треба виправити. Кожен інший елемент керування обмежує ввід під час редагування – повзунок не може вийти за свій діапазон, spinbox затискається у своїх межах – тож збережений файл завжди дійсний.

13.1.13.4. Довідник файлу конфігурації#

Типи елементів керування задокументовані на наведених нижче сторінках, згруповані за тим, що вони роблять.