Saltar a contenido

mte.ui — constructores de especificaciones de formulario

Todas las superficies de interfaz de la fase 3 — ctx.docks.add_panel y ctx.settings_page.register— toman una especificación de formulario: un diccionario simple que describe un árbol de widgets. Construye esas especificaciones con los ayudantes mte.ui.* para no tener que escribir el JSON a mano.

from mte.ui import (
    Column, Row, Group,
    Label, Button, Checkbox, LineEdit, NumberSpin, ComboBox, List,
)

Nada de mte.ui habla con Qt ni con PySide: cada ayudante devuelve un diccionario que sigue el esquema de canal que espera el analizador de formularios en C++ del anfitrión. Puedes componerlos, empalmar listas o generarlos mediante programación con toda libertad:

from mte.ui import Column, Row, Label, Button

def make_toolbar(commands):
    return Row([Button(text=c["label"], on_click=c["id"])
                for c in commands])

form = Column([Label(text="Actions:"),
               make_toolbar(my_commands)])

La especificación se valida en el lado del anfitrión; los tipos de control desconocidos o los campos obligatorios que falten producen un error InvalidParams que verás en el registro.

Las etiquetas de una especificación de formulario no se traducen

Todo rótulo que pongas en una especificación —títulos de panel, etiquetas de casillas, encabezados de grupo— se muestra exactamente como lo escribiste, sea cual sea el idioma de la interfaz. Son datos que tu plugin envía al editor, no cadenas que el editor pueda buscar en un catálogo de traducción. Si tu plugin debe hablar más de un idioma, elige tú mismo las cadenas antes de llamar a register; el idioma actual de la interfaz es ctx.app_settings.get_string(mte.keys.UI_LANGUAGE) (vacío significa «seguir al sistema»). Lo mismo vale para el name y la description que tu plugin.json muestra en Preferencias ▸ Complementos.


Disposiciones

Los constructores de disposición toman una lista de diccionarios hijos y los colocan vertical u horizontalmente.

Column(children)

Apila los hijos de arriba abajo con un estiramiento al final: los controles se quedan a su altura natural en vez de hincharse para llenar un panel alto.

Row(children)

La misma idea, de izquierda a derecha, con un estiramiento horizontal al final.

Group(children, *, title="")

Un marco con título (dibujado como QGroupBox) que contiene una pila vertical. Úsalo para agrupar visualmente controles relacionados:

Group([
    Checkbox(id="cs", label="Case sensitive", binds="settings:cs"),
    Checkbox(id="ww", label="Whole words",    binds="settings:ww"),
], title="Search options")

Las disposiciones se anidan libremente: una Row dentro de una Column dentro de un Group está bien.


Controles hoja

Todas las hojas aceptan los mismos cuatro enlaces compartidos mediante argumentos con nombre:

Argumento Significado
id= Identificador estable que usan ctx.ui.get / ctx.ui.set y (de forma implícita) binds.
binds= "settings:<key>" — se guarda automáticamente a través de ctx.settings.
on_click= Identificador de comando que invocar; solo en los botones.
on_change= Identificador de manejador (ctx.docks.on_change(...)); en todos los demás controles.

Solo las hojas que exponen un «valor» admiten binds y on_change.

Label(*, text="", id=None)

Texto estático.

Button(*, text, on_click=None, id=None)

Un botón pulsador. Disparar on_click invoca el comando registrado; si quieres mantener el botón sincronizado con otra cosa, puedes hacer ctx.ui.set sobre su text.

Checkbox(*, label="", default=False, id=None, binds=None, on_change=None)

Control booleano. default es el estado inicial; binds lo anula con el valor guardado, si existe alguno.

LineEdit(*, placeholder="", default="", id=None, binds=None, on_change=None)

Entrada de texto de una sola línea.

NumberSpin(*, default=0, min=None, max=None, step=1, id=None, binds=None, on_change=None)

Cuadro numérico con flechas. min y max acotan el intervalo (ambos opcionales; el QSpinBox subyacente usa su intervalo predeterminado cuando no se fijan). step es el incremento de las flechas.

Intervalo de int

NumberSpin se apoya en QSpinBox, que almacena un int (de 32 bits). Los valores fuera de -2_147_483_648 … 2_147_483_647 se saturarán en el límite de la plataforma.

ComboBox(*, items, default="", id=None, binds=None, on_change=None)

Desplegable. items es una lista: cada entrada puede ser una cadena simple o un objeto como {"value": "cpp", "label": "C++"} (hoy solo se usa value; label está reservado para un refinamiento futuro).

List(*, items, id=None, on_change=None)

Widget de lista con selección única. on_change se dispara con el texto del elemento recién seleccionado. Sin binds: guarda la selección tú mismo si la necesitas.


Acceso en tiempo de ejecución

Una vez registrado el panel, manéjalo desde cualquier comando:

panel_id = ctx.docks.add_panel(id="my.panel", ..., form=Column([
    LineEdit(id="needle"),
    Checkbox(id="cs"),
]))

# Read current values
needle = ctx.ui.get(panel_id, "needle")
cs     = ctx.ui.get(panel_id, "cs") == "true"

# Write values (does NOT fire on_change)
ctx.ui.set(panel_id, "needle", "hello")
ctx.ui.set(panel_id, "cs", True)

Consulta ctx.ui para la referencia completa.


Guardar valores

binds="settings:<key>" es la forma más corta de guardar el valor de un control:

  • Al construir el panel, el widget lee su valor inicial de ctx.settings.get(key, <default>).
  • En cada edición del usuario, el widget lo vuelve a escribir mediante ctx.settings.set(clave, nuevo_valor).

Como los paneles y las páginas de Preferencias comparten ctx.settings, dos controles con la misma cadena binds se reflejan mutuamente en tiempo real. Así es como el panel y la página de Preferencias de HelloPython mantienen sincronizada la casilla «Loud».

Si necesitas guardar algo que el vocabulario no cubre (por ejemplo, la selección de una List), lee y escribe directamente a través de ctx.settings en una retrollamada on_change.