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

Keyboard and focus

Tab follows the order you ADDED the fields, not where they ended up on screen. Build in reading order and the tab order is correct without being designed.

Qué muestra esto

Filling a form without touching the screen.

Every CrossFly app runs on the desktop, and on the desktop a form is filled with the keyboard. Tab walks the fields in the order they were added, which is why building a form in reading order is not only tidier — it is the tab order, for free. Build it out of order and the user tabs from the postcode back up to the surname.

Two style flags decide who can be reached. focusOnTouch means tapping this gives it the keyboard; focusOnKey means a keypress can move focus into it. A button that should be reachable by Tab needs the second, and a display-only panel wants neither — a Tab stop on something that does nothing is a Tab stop the user has to press through every time.

The other keyboard is the one you bring with you: NumericKeypad is an on-screen pad for a device that has no keys at all, or for a value that is only ever digits — a warehouse terminal, a scale, a till.

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.R27Focus"
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.

ButtonComponentHintLabelNumericKeypadScreenStylesTextFieldWidgets

El código

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

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

import dev.cf.Tones;

import dev.crossfly.ui.*;
import dev.crossfly.ui.color.*;
import dev.crossfly.ui.graphics.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.style.*;

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

/**
 * Filling a form without touching the screen.
 *
 * <p>Every CrossFly app runs on the desktop, and on the desktop a form is filled with the keyboard.
 * Tab walks the fields in the order they were <b>added</b>, which is why building a form in reading
 * order is not only tidier — it is the tab order, for free. Build it out of order and the user
 * tabs from the postcode back up to the surname.</p>
 *
 * <p>Two style flags decide who can be reached. {@code focusOnTouch} means tapping this gives it
 * the keyboard; {@code focusOnKey} means a keypress can move focus into it. A button that should
 * be reachable by Tab needs the second, and a display-only panel wants neither — a Tab stop on
 * something that does nothing is a Tab stop the user has to press through every time.</p>
 *
 * <p>The other keyboard is the one you bring with you: {@link NumericKeypad} is an on-screen pad
 * for a device that has no keys at all, or for a value that is only ever digits — a warehouse
 * terminal, a scale, a till.</p>
 */
public class R27Focus extends Recipe
{
   private Label reached;

   public String title()
   {
      return "Keyboard and focus";
   }

   public String note()
   {
      return "Tab follows the order you ADDED the fields, not where they ended up on screen. Build"
         + " in reading order and the tab order is correct without being designed.";
   }

   public void build(Component body) throws Exception
   {
      body.add(LAY_AUTO, outgap(label("Press Tab. It walks these in the order they were added.", 1f,
         false, Styles.captionColor, Position.START), 0, 0, 0, .8f));

      field(body, "Name");
      field(body, "Company");
      field(body, "Postcode");

      reached = label("Focus has not reached the button yet.", 1f, false, Styles.captionColor,
         Position.START);
      body.add(LAY_AUTO, outgap(reached, 0, .4f, 0, .6f));

      Button send = Tones.action("Send");
      // Reachable by keyboard, not only by pointer. Without this the last thing in the form is the
      // one thing a keyboard user cannot get to, and they have to reach for the mouse to finish.
      send.getStyle()
         .focusOnKey(true)
         .focusOnTouch(true);
      send.onAction(c -> Hint.show("Sent", 1500));
      send.testTag("focus.send");
      body.add(LAY_AUTO, outgap(send, 0, 0, 0, 1.4f));

      body.add(LAY_AUTO, Tones.head(0xE312, "A keypad of your own", Tones.highlight()));
      body.add(LAY_AUTO, outgap(label("For a device with no keyboard, or a value that is only ever"
         + " digits.", 1f, false, Styles.captionColor, Position.START), 0, 0, 0, .6f));

      final TextField total = new TextField();
      total.caption("Total");
      total.setMode(EditMode.CURRENCY);
      total.testTag("focus.total");
      body.add(LAY_AUTO, outgap(total, 0, 0, 0, .6f));

      // The keypad reports TOKENS, not characters — "0".."9", "," and BACK — so the screen decides
      // what each one means. That is what lets the same pad drive a currency field, a quantity and
      // a PIN without the pad knowing about any of them.
      NumericKeypad pad = new NumericKeypad(token ->
      {
         String now = total.getText();
         if (NumericKeypad.BACK.equals(token))
            total.setText(now.isEmpty() ? "" : now.substring(0, now.length() - 1));
         else
            total.setText(now + token);
         Screen.repaint();
      });
      pad.testTag("focus.keypad");
      body.add(LAY_AUTO, pad);
   }

   private void field(Component body, String caption) throws Exception
   {
      TextField f = new TextField();
      f.caption(caption);
      f.testTag("focus." + caption.toLowerCase());
      // Fired when the field takes the keyboard. On a phone this is where a screen scrolls the
      // field clear of the on-screen keyboard, which is what Device.shiftScreen is for.
      f.onFocus(c ->
      {
         reached.setText("Focus is on: " + caption);
         reached.setValidLayout(false);
         Screen.repaint();
      });
      body.add(LAY_AUTO, outgap(f, 0, 0, 0, .6f));
   }
}
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
AnteriorImagesSiguienteWriting your own component