# 从屏幕返回值

> 如何接收返回的结果——构造函数回调模式和 Picker/onAnswer 模式。

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

# 从屏幕返回值

有**两种**模式，选对模式可以避免一个常见的 bug。

## ⚠️ 关键点
`Window.show(onAnswer)` **只有当窗口是 `Picker` 时才会触发 `onAnswer`**（在内部，
`hide()` 执行 `answer = this instanceof Picker ? getAnswer() : null`，仅当
`answer != null` 时才调用回调）。对于**普通屏幕**（`Window` 的子类），`show(onAnswer)` **不**返回
值——请使用**构造函数回调**模式。

## 完整示例（复制、粘贴并运行）
```java
package com.exemplo;

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

/** 可执行的主界面。将 launcher 指向此类（classname）并运行：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");
      // 普通屏幕 → 回调通过构造函数传入（show(cb) 只在 Picker 中触发）。
      escolher.onAction(c ->
         new TelaSelecao(op -> resultado.setText("Escolheu: " + op)).show());
      add(LAY_AUTO, escolher);
   }
}

/** 普通屏幕，通过构造函数中接收的回调返回一个值。 */
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(); });   // 返回并关闭
      add(LAY_AUTO, a);

      Button b = new Button("Opção B");
      b.onAction(c -> { onEscolha.run("B"); hide(); });
      add(LAY_AUTO, b);
   }
}
```
> 下面的片段**仅展示核心部分**（放入 `onShow()` 内的内容）。要运行它们，请放入上面的 `MainWindow` 骨架中。

## 模式 1——构造函数回调（普通屏幕）
向屏幕的构造函数传递一个回调；它会在 `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(); });   // 返回并关闭
      add(LAY_AUTO, opa);
   }
}

// 用法：
new TelaSelecao(resultado -> System.out.println("Escolheu: " + resultado)).show();
```

## 模式 2——Picker + `onAnswer`（现成的选择器）
[选择器](/docs/ui/widgets/picker)（`DatePicker`、`TimePicker`、`ColorPicker` 等）已经实现了
`getAnswer()`。对它们使用 `show(onAnswer)`：
```java
new DatePicker().show(resposta -> {
   // 只在 != null 时触发（用户已确认；取消 ⇒ getAnswer() 为 null）
   System.out.println("Data: " + resposta);
});
```
要创建自己的选择器，请**继承 `Picker`** 并实现 `getAnswer()`。

## ⚠️ 对话框**不**使用 `onAnswer`
`Alert` 和 `ActionSheet` 继承自 `Window`（而非 `Picker`），因此 `show(callback)` **不会**触发。
响应通过**按钮的回调**（`buttonAction`）传入——参见[对话框与模态框](/docs/ui/navigation/dialogs-and-modals)。

## 最佳实践
- 普通屏幕 → **构造函数回调**。选择器 → **`Picker` + `onAnswer`**。
- 对于屏幕之间共享的状态，考虑使用 **ViewModel/controller**（参见
  [架构](/docs/best-practices)）。

## 常见错误
- 在**不是** `Picker` 的屏幕上使用 `minhaTela.show(cb)` 并期望 `cb` 触发（不会触发）。
- 使用 `alert.show(cb)`——回调永远不会运行；请使用 `buttonAction`。

## 另见
- [对话框与模态框](/docs/ui/navigation/dialogs-and-modals) · [Pickers（目录）](/docs/ui/widgets/picker)
