Saltar al contenido
CrossFly es 100% open sourceSíguenos en GitHub
CrossFlyCrossFly
Empezar

Esta página fue traducida automáticamente del portugués y puede contener errores. La versión en portugués es la canónica.

Tu primera app: lista de tareas

Vamos a construir una app que abre, añade, navega y persiste — paso a paso, introduciendo cada pieza en el orden de la necesidad.

Ejemplo completo (copiar, pegar y ejecutar)

Una versión reducida y autocontenida de lo esencial: un TextField + Button que añade elementos a una lista virtual. Pégalo en una clase MainWindow y ejecuta con gradlew :lwjgl3:run.

package com.exemplo;

import java.util.ArrayList;
import java.util.List;

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;

public class MainWindow extends Window
{
   private final List<String> tarefas = new ArrayList<>();
   private TextField campo;
   private VirtualListView lista;

   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      // fila de entrada: campo (absorbe el ancho) + botón (tamaño natural)
      Component entrada = new Component();
      entrada.setLayout(new HorizontalLayout());
      campo = new TextField().caption("Nova tarefa");
      Button add = new Button("Adicionar");
      entrada.add(LAY_FILL, campo);
      entrada.add(LAY_AUTO, add);
      add(LAY_AUTO, entrada);

      // lista virtual: cada celda tiene 3x la altura de la fuente
      lista = new VirtualListView(Relative.ofFont(3f), new DataAdapter()
      {
         @Override public int getCount() { return tarefas.size(); }
         @Override public Component createView() { return new Label(""); }
         @Override public void bindView(Component view, int index)   // view primero, después index
         {
            ((Label) view).setText(tarefas.get(index));   // cast directo
         }
      });
      add(LAY_FILL, lista);

      add.onAction(c -> adicionar());
   }

   private void adicionar()
   {
      String texto = campo.getText().trim();
      if (texto.isEmpty())
      {
         Hint.show("Digite uma tarefa", 1500);   // siempre 2 args
         return;
      }
      tarefas.add(texto);
      campo.clearText();
      lista.notifyDataChanged();   // re-mide y repinta la lista
   }
}

Los fragmentos de abajo muestran solo el meollo (lo que va dentro de onShow()). Para ejecutar, colócalos en el esqueleto MainWindow de arriba.

1. El esqueleto de la pantalla (VerticalLayout)

public class TarefasScreen extends Window {
   private final List<Tarefa> tarefas = new ArrayList<>();   // estado en campos de la Window
   private Component listaBox;
   private TextField campo;

   @Override public void onShow() throws Exception {
      super.onShow();
      setLayout(new VerticalLayout());

      // fila de entrada (campo + botón)
      Component entrada = new Component();
      entrada.setLayout(new HorizontalLayout());
      campo = new TextField().caption("Nova tarefa");
      Button add = new Button("Adicionar");
      entrada.add(LAY_FILL, campo);       // el campo absorbe el ancho
      entrada.add(LAY_AUTO, add);         // botón del tamaño del contenido
      add(LAY_AUTO, entrada);

      // área de la lista, que absorbe el resto de la altura
      listaBox = new Component();
      listaBox.setLayout(new VerticalLayout());
      add(LAY_FILL, listaBox);

      add.onAction(c -> adicionar());
      carregar();                          // puebla desde la base de datos
   }
}

2. Añadir y reflejar en la UI (sin binding reactivo)

private void adicionar() {
   String texto = campo.getText().trim();
   if (texto.isEmpty()) return;
   Tarefa t = new Tarefa(texto);
   tarefas.add(t);
   salvar(t);              // persiste (paso 4)
   campo.clearText();
   renderizarLista();      // tú actualizas la UI manualmente
}

private void renderizarLista() {
   listaBox.removeAll();
   for (Tarefa t : tarefas) {
      Button item = new Button(t.titulo);
      item.onAction(c -> new DetalheScreen(t).show());   // navegación (paso 3)
      listaBox.add(LAY_AUTO, item);
   }
   listaBox.setValidLayout(false);   // re-mide el layout
   Component.repaint();              // pide nuevo frame
}

3. Navegación push/pop

public class DetalheScreen extends Window {
   private final Tarefa tarefa;
   public DetalheScreen(Tarefa t) { this.tarefa = t; }   // datos por el constructor
   @Override public void onShow() throws Exception {
      super.onShow();
      setLayout(new VerticalLayout());
      add(LAY_AUTO, new Label(tarefa.titulo));
      Button voltar = new Button("Voltar");
      voltar.onAction(c -> hide());     // pop
      add(LAY_AUTO, voltar);
   }
}

4. Persistencia en SQLite (fuera de la paint thread)

private void carregar() {
   new Thread(() -> {
      List<Tarefa> carregadas = new ArrayList<>();
      try (SqliteDb db = SqliteDb.open("tarefas.db")) {
         db.exec("CREATE TABLE IF NOT EXISTS tarefa(id INTEGER PRIMARY KEY, titulo TEXT)");
         try (SqliteCursor c = db.query("SELECT id, titulo FROM tarefa ORDER BY id")) {
            while (c.next())                                   // getters 0-based
               carregadas.add(new Tarefa(c.getInt(0), c.getString(1)));
         }
      } catch (Exception e) { Debug.handle(e); }
      Component.onUI(() -> {                                   // vuelve al paint thread
         tarefas.clear(); tarefas.addAll(carregadas);
         renderizarLista();
      });
   }).start();
}

private void salvar(Tarefa t) {
   new Thread(() -> {
      try (SqliteDb db = SqliteDb.open("tarefas.db")) {
         db.execute("INSERT INTO tarefa(titulo) VALUES(?)", t.titulo);   // bind 1-based
      } catch (Exception e) { Debug.handle(e); }
   }).start();
}

Dos reglas de oro de SQLite: el bind de parámetro es 1-based, los getters del cursor son 0-based; y la base de datos corre fuera de la paint thread, con el resultado volviendo vía Component.onUI(...).

Lo que has construido

Una app que abre, añade, navega y persiste — y ya has visto los pilares que el curso learn/ profundiza.

Próximos pasos

→ Anatomía de un proyecto

Ver también

¿Te resultó útil esta página?