# Returning values from a screen

> How to receive a result back — the callback pattern and the Picker/onAnswer pattern.

Source: https://crossfly.dev/docs/ui/navigation/returning-results — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# 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)
```java
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()`:
```java
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](/docs/ui/widgets/picker) (`DatePicker`, `TimePicker`, `ColorPicker`, etc.) already implement
`getAnswer()`. For them, use `show(onAnswer)`:
```java
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](/docs/ui/navigation/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](/docs/best-practices)).

## 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
- [Dialogs and modals](/docs/ui/navigation/dialogs-and-modals) · [Pickers (catalog)](/docs/ui/widgets/picker)
