Manual docente · versión 0.5.1

SimpleUI para Processing

Una única librería para construir interfaces gráficas en proyectos de Processing Desktop y Processing for Android, acompañada de un calendario y del motor de tareas SimpleCore.

Autoría. SimpleUI y SimpleCore han sido diseñadas y desarrolladas por Luis López Martínez y se distribuyen bajo licencia MIT.
✓ Desktop y AndroidSimpleCore incluidoLicencia MIT

Una API reconocible

Botones, etiquetas, listas, tablas, campos de texto, calendarios y vistas comparten una estructura y un sistema de eventos coherentes.

Sketches limpios

La librería registra automáticamente los eventos de ratón, toque y teclado. El sketch conserva únicamente su lógica y el dibujo.

Dos plataformas

El código se mantiene casi idéntico. Solo cambia el import: simpleui.desktop.* o simpleui.android.*.

Tareas independientes

simplecore.* proporciona tareas con ciclo de vida, prioridad, señales y representación gráfica opcional.

Modelo mental

  1. Se inicializa SimpleUI con el sketch.
  2. Se crean controles y se añaden al registro global.
  3. Un único UIEventHandler recibe las acciones del usuario.
  4. updateAndDrawUI() actualiza y dibuja la interfaz en cada fotograma.
import simpleui.desktop.*; // En Android: import simpleui.android.*;

UIButton boton;

void setup() {
  size(640, 360);
  SimpleUI.initUI(this, "SansSerif", 18);
  boton = new UIButton("saludar", 30, 40, 180, 48, "Saludar", 18);
  SimpleUI.addUIElement(boton);
}

void draw() {
  background(SimpleUI.currentTheme.backgroundColor);
  SimpleUI.updateAndDrawUI();
}
Objetivo pedagógico. El alumno puede empezar con un botón y un evento, y avanzar después hacia colecciones, vistas, calendarios y tareas sin cambiar de paradigma.
Primeros pasos

Instalación y arranque

Desktop y Android

Instalar

Copia la carpeta completa SimpleUI dentro de la carpeta libraries del sketchbook de Processing. El archivo cargado por Processing es SimpleUI/library/SimpleUI.jar. Reinicia el IDE después de instalar o actualizar la librería.

Elegir el import

// Processing Desktop
import simpleui.desktop.*;

// Processing for Android
import simpleui.android.*;

// SimpleCore es común a las dos plataformas
import simplecore.*;

Esqueleto mínimo

import simpleui.desktop.*;

void settings() {
  size(800, 600);
}

void setup() {
  SimpleUI.initUI(this, "SansSerif", 18);
  SimpleUI.setMode(800, 600);
}

void draw() {
  background(SimpleUI.currentTheme.backgroundColor);
  SimpleUI.updateAndDrawUI();
}
setMode(anchoDiseño, altoDiseño) define la resolución virtual completa. SimpleUI calcula la escala y transforma tanto el dibujo como la entrada del ratón o la pantalla táctil.

Orden de dibujo

updateAndDrawUI() debe ejecutarse después del fondo y del contenido que tenga que quedar detrás de la interfaz. Si necesitas separar ambas fases, utiliza updateUI() y drawUI().

Arquitectura

Eventos automáticos

Desktop y Android

initUI() instala un puente de eventos mediante el ciclo de vida de Processing. No es necesario declarar mousePressed(), mouseDragged(), mouseReleased(), keyPressed() ni keyTyped() en el sketch.

Recibir eventos

SimpleUI.setUIEventHandler(new UIEventHandler() {
  public void onUIEvent(UIElement element, String action, Object data) {
    println(element.id + " → " + action + " → " + data);

    if (element.id.equals("guardar") && action.equals("clicked")) {
      guardarDatos();
    }
  }
});
ControlAcciónContenido de data
UIButtonclickednull
UICheckbox / UISwitchchangedboolean
UIDropdownchangedopción seleccionada
UISliderchangedfloat
UIListitemSelectedtexto seleccionado
UITablerowSelectedString[]
UITabstabChangedetiqueta seleccionada
Camposchanged, submittedtexto o número
UICalendardateSelectedUICalendarSelection

Control manual y teclado Android

setAutomaticEventHandling(false)

Desactiva el puente automático si una integración avanzada necesita reenviar los eventos manualmente.

setKeyEventInterceptor(interceptor)

Permite consumir una tecla antes de que llegue a SimpleUI; es útil para la tecla Atrás de Android.

detach()

Desregistra el puente y libera la referencia al sketch. Normalmente se ejecuta automáticamente en dispose.

No mezcles ambos modelos. Si el puente automático está activo, no reenvíes también los eventos desde funciones del sketch o cada interacción podría procesarse dos veces.
Compatibilidad

Desktop y Android

Las dos implementaciones viven en el mismo JAR, pero en paquetes separados para evitar dependencias Android al compilar un sketch Desktop.

CapacidadDesktopAndroid
Controles, eventos, vistas y calendario
SimpleCore
Teclado nativo y ajuste al teclado virtualTeclado Processing
UISignalMeter
UIRect
Footer y recibo de lectura en chatArea

Contrato común desde 0.5.0

  • Controles y modelos: todas las clases ofrecen los mismos constructores y métodos públicos en los dos paquetes.
  • Resolución virtual: setMode(), UIScaleMode y las conversiones de coordenadas funcionan igual en Desktop y Android.
  • UISwitch: ofrece una selección booleana compacta y emite changed.
  • UIDropdown: emite changed.
  • UISlider: emite changed durante el movimiento y released al terminar.
  • Modales: admiten tanto actionId con handler como callbacks Runnable.
  • chatArea: admite footer y recibo de lectura en ambas plataformas.
Portabilidad directa: el código de controles puede trasladarse cambiando únicamente el import. Solo los servicios del sistema Android —Activity, teclado virtual y pantalla activa— permanecen específicos de plataforma.
Clase coordinadora

SimpleUI

Desktop y AndroidMétodos estáticos

SimpleUI mantiene el host de Processing, la colección de controles, el tema, la escala, los estados de interacción y el receptor global de eventos.

API de uso habitual

initUI(this, fuente, tamaño)

Conecta el sketch, crea la fuente, carga el tema y registra los eventos.

setMode(ancho, alto)

Define una resolución virtual y usa el modo proporcional FIT.

setMode(ancho, alto, UIScaleMode)

Elige entre FIT, FILL y RESPONSIVE.

getLogicalWidth() / getLogicalHeight()

Devuelve el área disponible en coordenadas de diseño.

addUIElement(elemento)

Añade un control al registro global y al orden de dibujo.

getUIElement(id)

Busca un control por identificador; devuelve null si no existe.

removeUIElement(id)

Retira el control indicado y devuelve si fue encontrado.

clearUIElements()

Elimina todos los controles y limpia estados de interacción.

updateAndDrawUI()

Sincroniza, actualiza gestos y dibuja controles, menús, inputs y modales.

setUIEventHandler(handler)

Registra el receptor global de eventos.

setTheme(UIColorTheme.DARK)

Cambia entre tema oscuro y claro.

setUIAlpha(alpha)

Define opacidad global entre 0 y 255.

enableAllElements() / disableAllElements()

Activa o desactiva todos los controles registrados.

getUIToday()

Devuelve la fecha local actual como UIDate.

Estado público útil

currentTheme, uiScale, scaleMode, designWidth, designHeight, logicalWidth, logicalHeight, viewportOffsetX, viewportOffsetY, modeConfigured, uiElements, activeDropdown, activeTextField y activeUIModal permiten inspección avanzada. Para enseñanza inicial es preferible usar los métodos de alto nivel.

SimpleUI.LIBRARY_AUTHOR devuelve "Luis lopez martinez" y SimpleUI.LIBRARY_LICENSE devuelve "MIT". Las mismas constantes están disponibles en simplecore.Core.

Métodos internos. Las funciones de dibujo delegadas, resolución de gestos, búsqueda de elementos y handleUI…() son públicas por la forma en que se genera la librería, pero pertenecen a la infraestructura. No suelen llamarse desde un sketch.
Sistema de coordenadas

Resolución virtual y escala

Desktop y AndroidNuevo en 0.5.0

Diseña una sola vez con una resolución lógica —por ejemplo 1280 × 720— y deja que SimpleUI adapte dibujo, controles, modales y entrada a la ventana o pantalla real.

SimpleUI.initUI(this, "SansSerif", 18);
SimpleUI.setMode(1280, 720, UIScaleMode.RESPONSIVE);

void draw() {
  background(SimpleUI.currentTheme.backgroundColor);
  SimpleUI.updateAndDrawUI();
}

Modos disponibles

ModoComportamientoUso recomendado
FITConserva la proporción, muestra toda la resolución de diseño y centra el contenido. Puede dejar bandas libres.Interfaces de tamaño fijo que nunca deben recortarse.
FILLConserva la proporción y llena toda la superficie. El exceso queda fuera del viewport.Fondos o experiencias donde se admite recorte.
RESPONSIVEUsa la escala de FIT, pero expone el espacio sobrante como coordenadas lógicas adicionales.Ventanas redimensionables y distintas relaciones de aspecto en Android.
Modo predeterminado: setMode(1280, 720) equivale a setMode(1280, 720, UIScaleMode.FIT).

API del viewport

getLogicalWidth() / getLogicalHeight()

Dimensiones utilizables por el layout. En RESPONSIVE pueden superar la resolución base.

screenToDesignX(x) / screenToDesignY(y)

Convierte una coordenada física de la ventana a coordenadas lógicas.

designToScreenX(x) / designToScreenY(y)

Convierte una coordenada lógica a píxeles físicos.

updateViewport()

Recalcula manualmente escala y viewport. La actualización normal ya lo hace automáticamente.

Estado resuelto del viewport

CampoContenido
designWidth / designHeightResolución virtual solicitada mediante setMode().
logicalWidth / logicalHeightÁrea lógica resuelta. Para código de aplicación se recomiendan los getters equivalentes.
uiScaleFactor aplicado a dibujo e interacción.
viewportOffsetX / viewportOffsetYDesplazamiento físico, en píxeles de pantalla, usado para centrar FIT o recortar FILL.
scaleModeModo UIScaleMode actualmente activo.
modeConfiguredIndica si ya se ha definido una resolución virtual.
Campos de consulta. Aunque son públicos, trátalos como valores resueltos de solo lectura. Configura el sistema mediante setMode() y consulta las dimensiones mediante sus getters.

Layout adaptable

SimpleUI escala automáticamente cada control, pero no decide cómo repartir el espacio adicional de RESPONSIVE. Cuando cambien getLogicalWidth() o getLogicalHeight(), usa setPosition() y setSize() para ampliar tablas, paneles o áreas gráficas.

Coordenadas personalizadas. Si dibujas o compruebas impactos fuera de los controles SimpleUI, trabaja en coordenadas lógicas o usa las funciones de conversión. No dividas únicamente por uiScale: los modos centrados también tienen desplazamiento de viewport.
Clase base

UIElement

Desktop y AndroidClase abstracta
UIElement(String id, int x, int y, int width, int height)

Es la base de todos los controles. Define posición, dimensiones, identificador, visibilidad, activación y anclaje.

setPosition(x, y)

Mueve el control.

setSize(w, h)

Cambia sus dimensiones.

setVisible(boolean)

Controla si se dibuja y participa en la interfaz.

setEnabled(boolean)

Controla si acepta interacción.

setAnchored(boolean)

Marca un elemento fijo frente al desplazamiento global, especialmente útil en Android.

containsPoint(px, py)

Comprueba si unas coordenadas están dentro del rectángulo.

hasScrollableOverflow()

Indica si el control puede consumir un gesto vertical interno.

Los campos x, y, width, height, id, isVisible e isEnabled son públicos. Para código más legible, usa sus setters cuando existan.
Apariencia

Temas y configuración

Desktop y Android

UIColorTheme contiene los valores DARK y LIGHT. UIConfig representa los seis colores resueltos del tema.

SimpleUI.setTheme(UIColorTheme.DARK);
background(SimpleUI.currentTheme.backgroundColor);

int acento = SimpleUI.currentTheme.accentColor;
int texto   = SimpleUI.currentTheme.textColor;
Campo de UIConfigUso
backgroundColorFondo general del sketch.
surfaceColorSuperficies de controles y paneles.
textColorTexto principal.
accentColorSelección, progreso y énfasis.
borderColorBordes y separadores.
placeholderColorTexto orientativo de inputs.

Varios controles proporcionan setColors(), setTextColor() o setBorderColor() para sobrescribir localmente el tema.

Controles

UIButton y UIImageButton

Desktop y Android
UIButton(id, x, y, w, h, label, fontSize)
UIImageButton(id, x, y, w, h, PImage imagen)
UIImageButton(id, x, y, w, h, PImage imagen, imageW, imageH)

UIButton representa una acción textual. UIImageButton hereda su comportamiento y reemplaza la presentación por una imagen.

setLabel(texto)

Cambia el texto del botón.

setColors(relleno, borde, texto)

Activa colores personalizados.

setPressedVisual(boolean)

Fuerza el estado visual presionado.

setImage(PImage)

Cambia la imagen de UIImageButton.

setImageSize(w, h)

Define el tamaño dibujado de la imagen.

Evento clicked, con data == null.

UIButton guardar = new UIButton("guardar", 30, 30, 160, 46, "Guardar", 18);
SimpleUI.addUIElement(guardar);

// En onUIEvent:
if (element == guardar && action.equals("clicked")) {
  println("Datos guardados");
}
Controles

UILabel y UIIndicator

Desktop y Android
UILabel(id, x, y, w, h, texto, fontSize)
UIIndicator(id, x, y, size)

UILabel muestra texto no interactivo; UIIndicator dibuja un testigo circular de estado.

label.setText(texto)

Actualiza el contenido.

label.setTextAlignment(horizontal, vertical)

Usa constantes Processing como LEFT, CENTER, TOP.

indicator.setIndicatorColor(color)

Cambia el color del testigo.

indicator.setBorderColor(color)

Personaliza el borde; clearBorderColor() recupera el tema.

UILabel estado = new UILabel("estado", 60, 30, 260, 30, "Conectado", 18);
UIIndicator led = new UIIndicator("led", 30, 33, 20);
led.setIndicatorColor(color(30, 190, 100));
SimpleUI.addUIElement(estado);
SimpleUI.addUIElement(led);
Controles booleanos

UICheckbox y UISwitch

Desktop y AndroidUISwitch nuevo en 0.5.0
UICheckbox(id, x, y, size, label, fontSize)
UISwitch(id, x, y, w, h, label, initialValue, fontSize)

Ambos controles representan un valor booleano. UICheckbox usa una casilla tradicional; UISwitch ofrece un interruptor compacto con pista, cursor y etiqueta, integrado con escala, temas y eventos.

isChecked()

Consulta el estado actual.

setChecked(boolean)

Modifica el estado desde el programa sin emitir un evento.

setLabel(texto)

Cambia la etiqueta mostrada junto al interruptor.

toggle()

Invierte el estado y emite changed. No actúa si el control está deshabilitado.

Evento Los dos emiten changed; data contiene el nuevo boolean.

UICheckbox sonido = new UICheckbox("sonido", 30, 40, 24, "Activar sonido", 17);
sonido.setChecked(true);
SimpleUI.addUIElement(sonido);

UISwitch ordenar = new UISwitch(
  "ordenar", 30, 85, 250, 38,
  "Ordenar por intensidad", false, 16
);
SimpleUI.addUIElement(ordenar);

// En onUIEvent:
if (element == sonido && action.equals("changed")) {
  boolean activo = (Boolean)data;
}
if (element == ordenar && action.equals("changed")) {
  println((Boolean)data ? "Orden RSSI" : "Orden topológico");
}
Controles

UISlider y UIProgressBar

Desktop y Android
UISlider(id, x, y, w, h, min, max, initialValue, fontSize)

UIProgressBar(id, x, y, w, h)
slider.getValue() / setValue(v)

Consulta o cambia el valor, limitado al rango.

progress.setProgress(v)

Define progreso entre 0 y 1.

progress.getProgress()

Consulta el progreso.

progress.setColors(track, fill)

Personaliza pista y relleno.

UISlider emite changed con un float durante el movimiento y released al finalizar.

UISlider volumen = new UISlider("volumen", 30, 50, 280, 34, 0, 100, 50, 16);
UIProgressBar nivel = new UIProgressBar("nivel", 30, 105, 280, 18);
SimpleUI.addUIElement(volumen);
SimpleUI.addUIElement(nivel);

// En onUIEvent:
if (element == volumen && action.equals("changed")) {
  nivel.setProgress(((Float)data) / 100.0);
}
Colecciones visuales

UIList y UITable

Desktop y Android
UIList(id, x, y, w, h, fontSize)
UITable(id, x, y, w, h, String[] headers, float[] columnWidths, fontSize)

UIList

addItem(texto)

Añade una entrada.

getItemCount()

Número de entradas.

getSelectedIndex()

Índice seleccionado; -1 si no hay selección.

clearItems() / scrollToBottom()

Limpia o desplaza al final.

setTitle(texto)

Muestra una cabecera.

Evento itemSelected con el texto.

UITable

addRow(String[])

Añade una fila; debe corresponder con las columnas.

clearRows() / getRowCount()

Limpia o cuenta las filas.

scrollToBottom()

Muestra las últimas filas.

hasScrollableOverflow()

Indica si existen más filas que espacio visible.

minimumScroll()

Devuelve el límite inferior del desplazamiento interno.

Evento rowSelected con la fila como String[].

Cuando hay desbordamiento, la tabla muestra automáticamente un rail vertical y un cursor proporcional: cuanto mayor sea la parte visible del contenido, mayor será el cursor. Puede desplazarse con rueda, arrastre del contenido, arrastre del cursor o clic sobre el rail.

UITable alumnos = new UITable("alumnos", 30, 40, 520, 260,
  new String[]{ "Nombre", "Curso", "Nota" },
  new float[]{ .45, .30, .25 }, 16);
alumnos.addRow(new String[]{ "Ada", "Processing", "9.5" });
alumnos.addRow(new String[]{ "Alan", "Java", "8.7" });
SimpleUI.addUIElement(alumnos);
Entrada de datos

UITextField y UITextArea

Desktop y AndroidTeclado nativo Android
UITextField(id, x, y, w, h, placeholder, fontSize)
UITextArea(id, x, y, w, h, placeholder, fontSize)

UITextField introduce una sola línea. UITextArea admite varias líneas, ajuste de texto y desplazamiento interno.

getText() / setText(texto)

Lee o escribe el contenido.

setMaxLen(n)

Limita el número de caracteres.

setUppercase(boolean)

Convierte la entrada a mayúsculas.

setFocused(boolean) / isFocused()

Controla el foco.

submitAndCloseKeyboard()

Confirma y cierra el teclado.

setTextColor() / setBorderColor()

Personaliza los colores; los métodos clear…() recuperan el tema.

area.scrollToBottom()

Desplaza el área multilínea hasta el final.

Eventos changed durante la edición y submitted al confirmar; ambos entregan el texto.

UITextField nombre = new UITextField("nombre", 30, 40, 300, 44, "Tu nombre", 17);
nombre.setMaxLen(40);
UITextArea notas = new UITextArea("notas", 30, 105, 420, 150, "Observaciones", 16);
SimpleUI.addUIElement(nombre);
SimpleUI.addUIElement(notas);
Entrada de datos

UINumberField

Desktop y Android
UINumberField(id, x, y, w, h, placeholder, fontSize)
setAllowDecimal(boolean)

Permite o bloquea decimales.

setAllowNegative(boolean)

Permite o bloquea signo negativo.

setRange(min, max) / clearRange()

Define o elimina límites.

isValidNumber()

Comprueba que el texto es un número final válido.

getFloatValue() / getIntValue()

Devuelve el valor o null si no puede convertirse.

getText() / setText()

Accede a la representación textual.

Eventos changed entrega texto; submitted entrega Float o null.

UINumberField nota = new UINumberField("nota", 30, 40, 180, 44, "0 a 10", 17);
nota.setAllowDecimal(true);
nota.setAllowNegative(false);
nota.setRange(0, 10);
SimpleUI.addUIElement(nota);
Composición

UIPanel

Desktop y Android
UIPanel(id, x, y, w, h)

Superficie visual para agrupar controles. No contiene automáticamente otros elementos: el programador coloca los controles sobre sus coordenadas y debe añadir primero el panel para que quede detrás.

setTitle(texto, fontSize)

Añade título.

clearTitle()

Oculta el título.

setColors(fill, border, title)

Define colores personalizados.

clearCustomColors()

Recupera los colores del tema.

UIPanel panel = new UIPanel("datos", 20, 20, 420, 180);
panel.setTitle("Datos del alumno", 18);
SimpleUI.addUIElement(panel); // Primero: queda detrás
SimpleUI.addUIElement(new UITextField("nombre", 40, 70, 300, 42, "Nombre", 16));
Mensajería

chatArea

Desktop y Android
chatArea(id, x, y, w, h)

Área desplazable que presenta mensajes como burbujas a izquierda o derecha. El nombre público de la clase comienza en minúscula por compatibilidad con el código original.

addMessage(side, text)

Añade un mensaje. Usa lados coherentes en todo el proyecto, por ejemplo 0 izquierda y 1 derecha.

clearMessages()

Elimina el historial.

scrollToBottom()

Muestra el mensaje más reciente.

setPanelColor() / setLeftCardColor() / setRightCardColor()

Personaliza panel y burbujas.

Mensajes enriquecidos: en ambas plataformas existe addMessage(side, text, footer, readReceipt). ChatAreaMessage almacena side, text, footer y readReceipt.
chatArea chat = new chatArea("chat", 20, 30, 440, 300);
chat.addMessage(0, "¿Preparado para empezar?");
chat.addMessage(1, "Sí, vamos allá.");
chat.scrollToBottom();
SimpleUI.addUIElement(chat);
Telemetría

UISignalMeter

Desktop y Android
UISignalMeter(id, x, y, w, h, label)

Representa intensidad de señal a partir de RSSI en dBm y la traduce a segmentos y etiqueta de S-meter.

setLabel(texto)

Cambia la etiqueta.

setRssi(dbm)

Actualiza la medida.

setPending(boolean)

Muestra estado pendiente.

smeterLabelFromRssi()

Obtiene la etiqueta S correspondiente.

smeterSegmentsFromRssi()

Obtiene el número de segmentos.

UISignalMeter señal = new UISignalMeter("rssi", 30, 30, 300, 70, "LoRa");
señal.setRssi(-92);
SimpleUI.addUIElement(señal);
Interfaz avanzada

UIView y UIViewManager

Desktop y AndroidAvanzado

Una UIView agrupa controles que deben aparecer y desaparecer juntos. UIViewManager prepara vistas, cambia la vista activa y enruta sus eventos.

Ciclo de vida de una vista

initialize()

Obligatorio. Crea y registra controles una sola vez.

onShow()

Se ejecuta al mostrarse.

onHide()

Se ejecuta al ocultarse.

onDestroy()

Libera recursos propios.

addControl(elemento)

Asocia un control a la vista.

UIViewManager

prepare(view)

Inicializa sin mostrar.

show(view)

Oculta la actual y muestra la nueva.

hide(view) / destroy(view)

Oculta o destruye.

getActiveView()

Devuelve la vista activa.

routeEvent(element, action, data)

Entrega un evento a la vista propietaria.

UIViewManager paginas = new UIViewManager("principal");

class InicioView extends UIView {
  InicioView() { super("inicio", paginas); }

  public void initialize() {
    addControl(new UIButton("continuar", 30, 40, 180, 44, "Continuar", 17));
  }
}

InicioView inicio = new InicioView();
paginas.show(inicio);
Calendario

UICalendar

Desktop y Android
UICalendar(id, x, y, w, h)
UICalendar(id, x, y, w, h, UIDate initialDate)

Navegación y selección

showPreviousMonth() / showNextMonth()

Navega un mes.

showPreviousYear() / showNextYear()

Navega un año.

showToday()

Vuelve al mes actual.

setDisplayedMonth(year, month)

Muestra un mes concreto.

selectDate() / setSelectedDate()

Selecciona fecha y emite evento / fija la selección.

getSelectedDate() / clearSelection()

Consulta o limpia la selección.

Eventos de agenda

addEvent(id, fecha, título)

Añade un evento de un día.

addEvent(id, inicio, fin, título)

Añade un intervalo con UIDate o UIDateTime.

getEvent(id) / hasEvent(id) / removeEvent(id)

Gestiona por identificador.

getEventsForDate(fecha)

Obtiene una lista segura para esa fecha.

getEventsForDisplayedMonth()

Obtiene los eventos visibles.

clearEvents()

Vacía la agenda.

Eventos dateSelectedUICalendarSelection; selectionCleared; monthChanged, yearChanged y viewChangedUIDate.

UICalendar calendario = new UICalendar("agenda", 30, 30, 430, 350);
UIDate hoy = SimpleUI.getUIToday();
calendario.addEvent("clase", hoy, "Clase de Processing")
          .setColor(color(37, 99, 235))
          .setData("Aula 2");
SimpleUI.addUIElement(calendario);

// En onUIEvent:
if (element == calendario && action.equals("dateSelected")) {
  UICalendarSelection seleccion = (UICalendarSelection)data;
  println(seleccion.date + " · " + seleccion.events.size() + " eventos");
}

UICalendarEvent

Expone getId(), getTitle(), getStart(), getEnd(), getColor(), getData() e isVisible(). Sus setters encadenables son setTitle(), setColor(), setData(), setVisible() y setInterval(). También ofrece occursOn(), hasStarted(), hasFinished(), isActiveAt() y getDuration().

Modelo temporal

Fechas y tiempo

Desktop y Android

UIDate

UIDate(year, month, day)
UIDate(otraFecha)

Fecha inmutable con campos year, month y day. Valida la fecha al construirla.

isBefore / isAfter / isEqual

Comparaciones legibles; existen variantes …OrEqual.

differenceInDays(otra)

Diferencia con signo; absoluteDifferenceInDays() devuelve valor absoluto.

plusDays(n)

Crea una nueva fecha desplazada.

toUtcMillis()

Convierte la medianoche UTC a milisegundos.

UIDateTime

UIDateTime(y, m, d, hour, minute, second)
UIDateTime(y, m, d, hour, minute, second, millisecond, timeZoneId)

Fecha y hora inmutable. Ofrece getDate(), comparaciones, toEpochMilliseconds(), difference() y differenceInMilliseconds().

UITimeSpan

UITimeSpan(totalMilliseconds)

Duración con totales en milisegundos, segundos, minutos, horas o días; partes de días/horas/minutos/segundos; isNegative() y absolute().

UIDate inicio = new UIDate(2026, 9, 15);
UIDate examen = inicio.plusDays(30);
println(inicio.differenceInDays(examen));

UIDateTime entrada = new UIDateTime(2026, 9, 15, 9, 0, 0);
UIDateTime salida  = new UIDateTime(2026, 9, 15, 11, 30, 0);
UITimeSpan duracion = salida.difference(entrada);
println(duracion.getTotalMinutes()); // 150

UIDateComparator, UIDateTimeComparator y UICalendarEventDateComparator son comparadores auxiliares usados para ordenar colecciones.

Motor de tareas

Core

Desktop y Android · paquete simplecoreSingleton estricto

Core coordina tareas en cada fotograma. Solo puede existir una instancia ligada a un único PApplet.

Core.start(this)

Crea la instancia o devuelve la existente si pertenece al mismo sketch.

Core.getInstance()

Obtiene la instancia; lanza excepción si no se inició.

Core.isRunning()

Indica si hay instancia activa.

Core.shutdown()

Desregistra callbacks, destruye tareas y permite un reinicio limpio.

getTaskById(id)

Busca una tarea por su entero positivo.

getTaskCount() / getTasksSnapshot()

Consulta el estado sin exponer la colección interna.

signal(task, señal)

Envía una señal a una tarea.

signal(type, señal)

Envía a todas las tareas de un tipo.

signal(className, señal)

Envía por nombre de clase.

letMeAlone()

Desde una tarea, elimina las demás que no estén protegidas.

Señales

ConstanteResultado
SIGNAL_KILLMarca para destruir, salvo protección.
SIGNAL_PROTECTActiva protección contra kill.
SIGNAL_UNPROTECTRetira la protección.

Representación

El renderizado automático está activo. Usa setAutomaticRendering(false) y llama renderTasks() cuando necesites controlar las capas. setTaskCanvasScale() aplica una escala común a todas las tareas gráficas.

Importante: crear una Task antes de Core.start(this) produce una excepción. Intentar iniciar el singleton con otro sketch también produce una excepción.
Motor de tareas

Task

Desktop y Android

Una tarea encapsula estado y comportamiento actualizado por fotogramas. Se registra automáticamente al ejecutar su constructor.

Ciclo de vida que se sobrescribe

protected void initialize()

Una vez, justo antes del primer frame().

protected void frame()

Una vez por fotograma mientras la tarea esté viva.

protected void onDestroy()

Una sola vez al destruirse.

protected void render()

Dibujo; la implementación base representa graph con transformaciones.

import simplecore.*;

class Pelota extends Task {
  Pelota(PImage imagen) {
    setGraph(imagen).setPosition(80, 120).setZ(10);
  }

  protected void initialize() {
    priority = 5;
  }

  protected void frame() {
    advance(0, 2);        // 0° = derecha
    setAngle(angle + 1);
    if (x > width + 50) kill();
  }

  protected void onDestroy() {
    println("Pelota destruida: " + id);
  }
}

void setup() {
  size(640, 360);
  Core.start(this);
  new Pelota(loadImage("pelota.png"));
}

Estado y API

id, type, className, father, liveFrames

Identidad, clasificación, relación y edad.

priority

Las prioridades mayores actualizan primero.

properties

StringDict para datos adicionales.

kill() / setKillProtection()

Controlan la vida y protección.

setGraph() / clearGraph()

Asigna imagen de representación.

setPosition(), setZ(), setScale(), setAxisScale()

Transformaciones encadenables.

setAngle(), setAlpha(), setTint(), setVisible()

Apariencia encadenable.

getDist(task) / getAngle(task)

Relación espacial con otra tarea.

advance(ángulo, distancia)

Desplaza usando grados.

exists() / isDrawable()

Consulta estado.

Sin red. SimpleCore no contiene NetMessage, onNetMessage() ni conversiones de rutas. La comunicación de red puede añadirse después mediante una interfaz del proyecto.
Itinerario para el aula

52 sketches: 26 parejas Desktop y Android

Cada ejercicio Desktop tiene una versión Android equivalente. Los nombres y la estructura se mantienen para que el alumno pueda comparar ambas plataformas línea por línea.

01 a 09

Botones, imagen, etiqueta, indicador, checkbox, slider, progreso, desplegable y pestañas.

10 a 18

Lista, tabla, entradas de texto y número, panel, chat, medidor RSSI y calendario.

19 a 21

Miniaplicaciones de login, confirmación modal y navegación mediante vistas.

22 a 25

SimpleCore: ciclo de vida, minijuego, partículas y reacción al ratón o al dedo.

26

UISwitch: valor booleano compacto, estado inicial y evento changed.

Convención de nombres

Por ejemplo, Desktop06Slider y Android06Slider forman una pareja. Cada carpeta contiene un sketch independiente cuyo archivo principal tiene el mismo nombre que la carpeta.

Principios didácticos

  • Variables con nombres que explican su función.
  • Un único concepto nuevo por ejemplo de control.
  • Sin recursos externos: iconos y sprites se generan por código.
  • Sin callbacks manuales de ratón o teclado; se utiliza el puente automático de SimpleUI.
Orden sugerido: 01, 05, 06 y 26 para introducir eventos y estados; 10, 12 y 18 para trabajar datos; 19 a 21 para construir aplicaciones; 22 a 25 para introducir tareas y animación.
Login didáctico: el campo de clave no está enmascarado. El ejemplo enseña composición y validación, no autenticación segura.
Guía docente

Recetas y buenas prácticas

Un identificador único por control

El campo id permite localizar controles y depurar eventos. Usa nombres semánticos como "guardarAlumno" y evita reutilizarlos.

Orden de capas

Los controles se dibujan en el orden en que se añaden. Añade primero paneles y fondos; después campos y botones. Dropdowns y modales reciben tratamiento especial para quedar accesibles.

Comprueba acción y elemento

public void onUIEvent(UIElement element, String action, Object data) {
  if (element.id.equals("edad") && action.equals("submitted")) {
    Float edad = (Float)data;
    if (edad != null) println("Edad: " + edad);
  }
}

Actualiza, no recrees

Crea los controles en setup() o en UIView.initialize(). Durante draw(), modifica su contenido con setters. No construyas y registres controles en cada fotograma.

Define una resolución de diseño

Escoge un ancho y un alto lógicos —por ejemplo 1280 × 720— y llama a setMode(1280, 720). Usa UIScaleMode.RESPONSIVE si el layout debe aprovechar el espacio adicional de ventanas redimensionables o pantallas con otra proporción.

Reorganiza solo cuando cambie el viewport

En un layout responsive, guarda el último valor de getLogicalWidth() y getLogicalHeight(). Recalcula posiciones y tamaños únicamente cuando cambien; evita hacerlo innecesariamente cada fotograma.

Limpieza

SimpleUI.detach() y Core.shutdown() existen para reinicios controlados y tests. En el cierre normal, ambas partes usan callbacks dispose.

Secuencia recomendada para clase: botón → eventos → inputs → listas → vistas → calendario → tareas. Cada etapa reutiliza los conceptos de la anterior.
Distribución

Licencia MIT

Software libre permisivo

SimpleUI y SimpleCore han sido diseñadas y desarrolladas por Luis López Martínez. Copyright © 2026 Luis López Martínez.

La biblioteca se distribuye bajo licencia MIT. Permite usar, copiar, modificar, fusionar, publicar, distribuir, sublicenciar y vender copias, conservando el aviso de copyright y la licencia.

El software se proporciona «tal cual», sin garantías. Consulta el archivo LICENSE incluido en la raíz de la biblioteca para leer el texto legal completo.

Datos de esta versión

NombreSimpleUI
Versión0.5.1
Diseño y desarrolloLuis López Martínez
Copyright© 2026 Luis López Martínez
LicenciaMIT
Paquetessimpleui.desktop, simpleui.android, simplecore
Artefactolibrary/SimpleUI.jar
Última actualización24 de julio de 2026
Palabras claveGUI, widgets, controles, interfaces, Desktop, Android, Processing

Compatibilidad comprobada

  • Windows: compilación y pruebas completas con Processing 4.5.2.
  • Android: compilación con Android Mode 4.6.1, Android API 33 y conversión D8.
  • macOS y Linux: pendientes de verificación por la comunidad.

No incluye dependencias de ejecución de terceros. Processing 4 es necesario y los sketches Android requieren instalar Android Mode.

Código fuente y seguimiento del proyecto · Descargar la última versión