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 theMainWindowskeleton 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 thecbto fire on a screen that is not aPicker(it doesn’t fire). - Using
alert.show(cb)— the callback never runs; usebuttonAction.