Saltar al contenido
CrossFly es 100% open sourceSíguenos en GitHub
CrossFlyCrossFly
Empezar
Todos los ejemplos
RecetasAvisos131 líneas · 1 archivos

Waiting

Known length gets a bar. Unknown gets a spinner. A finished measurement — a share, a score — gets a ring, and that one is not waiting at all.

Qué muestra esto

Making the user wait, in the three shapes waiting actually comes in.

The choice is not decoration: it is whether you know how long. A spinner over a job whose length you know throws away the only reassurance the user wants; a percentage over a job whose length you are guessing is a lie they will catch at 99%.

Ejecutarlo en tu máquina

Cada ejemplo es una Window normal, así que el lanzador solo necesita su nombre.

gradlew lwjgl3:run --args="classname dev.cf.recipe.R13Waiting"
Editarlo

Java se compila antes de ejecutarse, así que el navegador no puede reconstruir una edición por su cuenta: el código que ves aquí se convirtió en JavaScript con TeaVM antes de publicarse. Copia el archivo a un proyecto y funciona sin cambios en las cuatro plataformas; el comando de arriba es toda la preparación.

Ejecutándose aquíCrossFly 0.1.32
Iniciando la aplicación…

Compilado a JavaScript por TeaVM: es el mismo código, no un vídeo de él. · Todos los ejemplos

Qué usa

Tipos del framework que toca este ejemplo. Los enlazados tienen página de referencia.

ButtonComponentMainPalColorPlatformUtilsProgressRadialProgressRelativeScreenSkinStylesWidgets

El código

Completo, sin recortes. Es el archivo, no un fragmento.

Crudo
dev/cf/recipe/R13Waiting.java
package dev.cf.recipe;

import dev.cf.Tones;

import dev.crossfly.Main;
import dev.crossfly.PlatformUtils;
import dev.crossfly.ui.*;
import dev.crossfly.ui.color.*;
import dev.crossfly.ui.graphics.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.skin.Skin;
import dev.crossfly.ui.style.*;

import static dev.crossfly.ui.Widgets.*;

/**
 * Making the user wait, in the three shapes waiting actually comes in.
 *
 * <p>The choice is not decoration: it is whether you know how long. A spinner over a job whose
 * length you know throws away the only reassurance the user wants; a percentage over a job whose
 * length you are guessing is a lie they will catch at 99%.</p>
 */
public class R13Waiting extends Recipe
{
   private Progress bar;
   private RadialProgress ring;
   private boolean running;

   public String title()
   {
      return "Waiting";
   }

   public String note()
   {
      return "Known length gets a bar. Unknown gets a spinner. A finished measurement — a share, a"
         + " score — gets a ring, and that one is not waiting at all.";
   }

   public void build(Component body) throws Exception
   {
      head(body, 0xE88B, "Unknown length", Tones.support());
      Progress spin = new Progress(Styles.progressType());
      spin.style(Skin.get()
         .progress()
         .autoWidth(Relative.ofFont(12f)));
      body.add(LAY_AUTO, outgap(spin, 0, 0, 0, 1.2f));

      head(body, 0xE9E4, "Known length", Tones.accent());
      bar = new Progress(0f, 1f);
      bar.style(Skin.get()
         .progress()
         .autoWidth(Relative.ofFont(16f)));
      body.add(LAY_AUTO, outgap(bar, 0, 0, 0, .5f));
      Button go = Tones.action("Run it");
      go.onAction(c -> run());
      body.add(LAY_AUTO, outgap(go, 0, 0, 0, 1.2f));

      head(body, 0xE6C4, "Not waiting — a measurement", Tones.highlight());
      ring = new RadialProgress().progress(.41f)
         .text("41%")
         .caption("converted");
      body.add(LAY_AUTO, ring);
   }

   /**
    * The work runs off the paint thread and reports back through it.
    *
    * <p>Advancing the bar from the paint thread means the bar cannot advance: the thread that would
    * draw it is the thread doing the work. This is the single most common reason a progress bar
    * jumps from 0 to 100 with nothing in between.</p>
    *
    * <p><b>And "off the paint thread" has two shapes, because one platform has one thread.</b>
    * {@link PlatformUtils#hasThreads()} is false in the browser: there the work is cut into slices
    * and each slice runs from a timer, so the page paints between them. Asking the question instead
    * of assuming a thread is what makes this recipe correct on all five &mdash; until 28/09/2026 it
    * started a {@code Thread} unconditionally, which is exactly the code a reader would copy.</p>
    */
   private void run()
   {
      if (running)
         return;
      running = true;
      if (!PlatformUtils.instance.hasThreads())
      {
         final int[] step = {0};
         final com.badlogic.gdx.utils.Timer.Task[] task = new com.badlogic.gdx.utils.Timer.Task[1];
         task[0] = addTimer(() ->
         {
            // One slice of work per tick: this runs ON the paint thread, so it must be short.
            bar.setValue(++step[0] / 20f);
            Screen.repaint();
            if (step[0] >= 20)
            {
               removeTimer(task[0]);
               running = false;
            }
         }, .09f);
         return;
      }
      new Thread(() ->
      {
         for (int i = 1; i <= 20; i++)
         {
            final float f = i / 20f;
            Main.runOnPaintThread(() ->
            {
               bar.setValue(f);
               Screen.repaint();
            });
            try
            {
               Thread.sleep(90);
            }
            catch (InterruptedException e)
            {
               Thread.currentThread()
                  .interrupt();
               break;
            }
         }
         running = false;
      }, "recipe-progress").start();
   }

   private void head(Component body, int icone, String t, PalColor tom) throws Exception
   {
      body.add(LAY_AUTO, Tones.head(icone, t, tom));
   }
}
Para una IA

Versiones de esta página legibles por máquina, para que un modelo lea el estante en vez de adivinar la API.

Este ejemplo, en JSONEste ejemplo, en Markdown
AnteriorBottom nav that becomes a railSiguienteCards that reflow