Skip to content
CrossFly is 100% open sourceFollow us on GitHub
CrossFlyCrossFly
Get started

This page was machine-translated from Portuguese and may contain errors. The Portuguese version is canonical.

Returning values from a screen

There are two patterns, and choosing the right one avoids a common bug.

⚠️ Critical point

Window.show(onAnswer) only fires onAnswer if the window is a Picker (internally, hide() does answer = this instanceof Picker ? getAnswer() : null and only calls the callback if answer != null). For an ordinary screen (subclass of Window), show(onAnswer) does not return a value — use the callback-through-the-constructor pattern.

Complete example (copy, paste and run)

package com.exemplo;

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.style.*;
import dev.crossfly.util.*;   // RunnableWith

/** Runnable main screen. Point the launcher (classname) and run: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      Label resultado = new Label("Nenhuma escolha ainda");
      add(LAY_AUTO, resultado);

      Button escolher = new Button("Escolher opção");
      // Common screen → callback VIA THE CONSTRUCTOR (show(cb) only fires on Picker).
      escolher.onAction(c ->
         new TelaSelecao(op -> resultado.setText("Escolheu: " + op)).show());
      add(LAY_AUTO, escolher);
   }
}

/** Common screen that returns a value via the callback received in the constructor. */
class TelaSelecao extends Window
{
   private final RunnableWith<String> onEscolha;

   public TelaSelecao(RunnableWith<String> onEscolha) { this.onEscolha = onEscolha; }

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

      Button a = new Button("Opção A");
      a.onAction(c -> { onEscolha.run("A"); hide(); });   // returns and closes
      add(LAY_AUTO, a);

      Button b = new Button("Opção B");
      b.onAction(c -> { onEscolha.run("B"); hide(); });
      add(LAY_AUTO, b);
   }
}

The snippets below show only the core (what goes inside onShow()). To run them, place them in the MainWindow skeleton above.

Pattern 1 — callback through the constructor (ordinary screens)

Pass a callback to the screen’s constructor; it invokes it before hide():

public class TelaSelecao extends Window {
   private final RunnableWith<String> onEscolha;
   public TelaSelecao(RunnableWith<String> onEscolha) { this.onEscolha = onEscolha; }

   @Override public void onShow() throws Exception {
      super.onShow();
      setLayout(new VerticalLayout());
      Button opa = new Button("Opção A");
      opa.onAction(c -> { onEscolha.run("A"); hide(); });   // returns and closes
      add(LAY_AUTO, opa);
   }
}

// usage:
new TelaSelecao(resultado -> System.out.println("Escolheu: " + resultado)).show();

Pattern 2 — Picker + onAnswer (ready-made selectors)

The pickers (DatePicker, TimePicker, ColorPicker, etc.) already implement getAnswer(). For them, use show(onAnswer):

new DatePicker().show(resposta -> {
   // only fires if != null (user confirmed; cancel ⇒ getAnswer() null)
   System.out.println("Data: " + resposta);
});

To create your own selector, extend Picker and implement getAnswer().

⚠️ Dialogs do NOT use onAnswer

Alert and ActionSheet extend Window (not Picker), so show(callback) does not fire. The response comes through the button callbacks (buttonAction) — see Dialogs and modals.

Best practices

  • Ordinary screens → callback in the constructor. Selectors → Picker + onAnswer.
  • For state shared between screens, consider a ViewModel/controller (see architecture).

Common mistakes

  • Using minhaTela.show(cb) expecting the cb to fire on a screen that is not a Picker (it doesn’t fire).
  • Using alert.show(cb) — the callback never runs; use buttonAction.

See also

Was this page helpful?