Pular para o conteúdo
CrossFly é 100% open sourceSiga no GitHub
CrossFlyCrossFly
Começar
Todos os exemplos
ReceitasEntrada110 linhas · 1 arquivos

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.

O que isto mostra

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.

Rodar na sua máquina

Todo exemplo é uma Window comum, então o launcher só precisa do nome dela.

gradlew lwjgl3:run --args="classname dev.cf.recipe.R27Focus"
Editar o exemplo

Java é compilado antes de rodar, então o navegador não consegue reconstruir uma edição sozinho — o código que você vê aqui virou JavaScript pelo TeaVM antes de ser publicado. Copie o arquivo para um projeto e ele roda sem mudanças nas quatro plataformas; o comando acima é toda a preparação.

Rodando aquiCrossFly 0.1.32
Iniciando o aplicativo…

Compilado para JavaScript pelo TeaVM — é o mesmo código, não um vídeo dele. · Todos os exemplos

O que ele usa

Tipos do framework que este exemplo toca. Os que têm link têm página de referência.

ButtonComponentHintLabelNumericKeypadScreenStylesTextFieldWidgets

O código

Completo, sem cortes. É o arquivo, não um trecho dele.

Bruto
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 uma IA

Versões desta página legíveis por máquina, para um modelo ler a prateleira em vez de adivinhar a API.

Este exemplo, em JSONEste exemplo, em Markdown
AnteriorImagesPróximoWriting your own component