13.1.13. O editor de definições#
Muitas aplicações de câmara precisam de um punhado de definições que um não-programador possa alterar – um limiar, um modo, uma palavra-passe de Wi-Fi – sem tocar no script. O OpenMV Cam Settings Editor é a ferramenta do IDE para isso: um ficheiro JSON descreve os controlos, o editor transforma essa descrição num formulário, e o seu script lê de volta os valores guardados com json.load(). O ficheiro é simultaneamente a configuração e a definição do seu próprio editor, pelo que a mesma configuração que armazena os valores também dispõe a interface gráfica para os editar.
O submenu Tools → OpenMV Cam Settings Editor contém as suas três ações.
Open OpenMV Cam Settings Config File lê a configuração da unidade da câmara ligada e abre-a no editor; ao guardar, escreve-a de volta na câmara.
Open Config File faz o mesmo para um ficheiro
.jsonno seu computador, para preparar uma configuração offline.Create Default Config escreve uma configuração inicial no disco e abre-a – um exemplo que exercita todos os tipos de controlo, pronto a ser reduzido às definições de que a sua própria aplicação necessita.

O editor de definições com a configuração predefinida aberta – os controlos do ficheiro JSON dispostos como um formulário (separadores, controlos deslizantes, listas pendentes, caixas de seleção), com Save e Cancel na parte inferior.#
13.1.13.1. Anatomia de um ficheiro de configuração#
Um ficheiro de configuração é um único objeto JSON com duas chaves:
title (string, opcional) – o título da janela do editor. A predefinição é
OpenMV Cam Settings Editor.controls (array, obrigatório) – a lista de objetos de controlo que o editor apresenta, por ordem, como linhas de um formulário. É toda a interface gráfica.
{
"title": "Camera Settings",
"controls": [
{ "type": "slider", "name": "threshold", "label": "Threshold", "value": 50 },
{ "type": "checkbox", "name": "draw_overlays", "label": "Draw Overlays", "value": true }
]
}
Cada entrada em controls é um controlo – um campo de texto, um número, uma checkbox, uma lista pendente, um slider, um group, uma barra de separadores, um label estático, e assim por diante. O seu type seleciona o widget; o resto do objeto configura-o. Quaisquer chaves que o editor não reconheça ficam intactas quando o ficheiro é guardado, pelo que pode manter os seus próprios metadados no ficheiro juntamente com os controlos.
13.1.13.3. Guardar e ler valores#
Um controlo que guarda um valor – uma checkbox, um slider, um campo de texto – transporta-o numa chave value. Quando clica em Guardar, o editor escreve o value atual de cada controlo de volta nesse mesmo objeto de controlo, no lugar, e reescreve o ficheiro. O ficheiro mantém a sua estrutura: nada se move, apenas as chaves value mudam. Não existe um mapa plano separado de name para valor – os valores residem dentro dos controlos, precisamente onde são definidos.
É por isso que a disposição é importante para o seu script. Os arrays controls e tabs mantêm a ordem em que os criou, pelo que o ficheiro não pode ser indexado por nome como um dicionário – config["controls"]["threshold"] não funciona. Este pequeno auxiliar preenche essa lacuna: dê-lhe o caminho de nomes até ao valor que pretende, e ele percorre a árvore por si.
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"]
Cada passo do caminho é o name de um controlo, ou o title de um separador (um separador não tem name próprio, embora possa adicionar um e este seja mantido). A barra de separadores e qualquer group que não tenha nomeado são transparentes – o find percorre-os – pelo que lista apenas os separadores e os controlos que rotulou, próximo de uma consulta aninhada config[...][...]. Um group nomeado é um passo próprio, pelo que o find pode também devolver o valor da sua caixa de verificação. Atribua a cada controlo um name único para que um caminho nunca seja ambíguo. O Exemplo completo lê valores da disposição de demonstração aninhada.
Como a configuração é simplesmente JSON, nada no seu script depende do editor – o editor limita-se a escrever o ficheiro que o seu script já lê. Um dispositivo pode transportar a sua configuração e uma forma acessível de a alterar, enquanto o script continua a ser um simples leitor de valores.
Um tipo de controlo impõe a sua entrada ao Guardar: um lineedit com uma mask ou regex recusa deixar o editor guardar enquanto o seu texto for inválido ou incompleto, e indica os campos a corrigir. Todos os outros controlos restringem a entrada à medida que edita – um slider não pode sair do seu intervalo, um spinbox limita-se aos seus limites – pelo que um ficheiro guardado é sempre válido.
13.1.13.4. Referência do ficheiro de configuração#
Os tipos de controlo estão documentados nas páginas abaixo, agrupados pelo que fazem.