# 如何从一个界面接收结果

> 打开一个界面并接收返回值 —— picker 通过 show(onAnswer)，普通界面通过构造函数中的回调。

Source: https://crossfly.dev/zh/docs/cookbook/nav/receber-resultado — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# 如何从一个界面接收结果

**目的。** 你打开一个界面让用户选择/填写某些内容，并需要拿回该值。CrossFly 有 **两种不同的机制**：`show(onAnswer)` 用于 **picker**，而 **构造函数中的回调** 用于普通界面。

## 使用的 API
- `Window.show(RunnableWith<Object> onAnswer)` — 注册一个结果回调。在源码中，该回调 **只在 `getAnswer() != null` 时才触发**，而 `Window.getAnswer()` 默认返回 `null` —— **只有 `Picker` 重写了** `getAnswer()`。也就是说：对于普通界面，这个回调 **永远不会触发**。
- `Picker.getAnswer()` — 返回所选的值，若取消则返回 `null`。只有 picker 实现了它。
- 构造函数中的回调 —— 普通界面的标准做法：将一个 `RunnableWith<T>`（或你自己的接口）传给界面的构造函数，并在 `hide()` 之前调用它。

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

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;

/** 可执行主屏：打开选择屏并通过构造函数中的回调接收结果。 */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      add(new Label("Nenhum cliente escolhido"));
      add(new Button("Escolher cliente").onAction(e ->
         // 普通屏 — 结果通过构造函数中的回调返回（此处 show(onAnswer) 不生效）。
         new SelecionarClienteTela(cliente -> Hint.show("Escolhido: " + cliente.nome, 1500)).show()));
   }
}

/** 简单的示例模型。 */
class Cliente
{
   final String nome;
   Cliente(String nome) { this.nome = nome; }
}

/** 选择屏：在关闭前通过构造函数回调交付结果。 */
class SelecionarClienteTela extends Window
{
   private final RunnableWith<Cliente> onPick;

   public SelecionarClienteTela(RunnableWith<Cliente> onPick) { this.onPick = onPick; }

   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());
      add(new Button("Escolher Ana").onAction(e ->
      {
         if (onPick != null) onPick.run(new Cliente("Ana"));  // 交付结果
         hide();                                              // 然后关闭
      }));
   }
}
```

> 下面的片段只展示 **核心部分**。要运行它，请把它放进上面的 `MainWindow` 骨架里。

## 最小片段
```java
// 已在源码核对：仅当 (this instanceof Picker) 且 answer != null 时 hide() 才调用 onAnswer.run(answer)

// 1) PICKER — 使用 show(onAnswer)。仅在结果非空（已确认选择）时触发。
DatePicker picker = new DatePicker(/* ... */);
picker.show(answer ->
{
   Date d = (Date) answer;      // 此处绝不为 null；取消不会触发回调
   Hint.show("Data: " + d, 1500);
});

// 2) 普通屏 — 结果通过构造函数中的回调返回（此处 show(onAnswer) 不生效）。
public class SelecionarClienteTela extends Window
{
   private final RunnableWith<Cliente> onPick;

   public SelecionarClienteTela(RunnableWith<Cliente> onPick) { this.onPick = onPick; }

   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new GridLayout());
      add(new Button("Escolher Ana").onAction(e ->
      {
         if (onPick != null) onPick.run(new Cliente("Ana"));  // 交付结果
         hide();                                              // 然后关闭
      }));
   }
}

// 调用：
new SelecionarClienteTela(cliente -> Hint.show("Escolhido: " + cliente.nome, 1500)).show();
```

为什么有两条路径？`hide()` 只为 `Picker` 调用 `onAnswer`（`instanceof Picker` 就写在 `Window.hide()` 的代码里）。对于普通界面，构造函数中的回调是明确的约定 —— 而且它允许为结果指定类型（`RunnableWith<Cliente>`），而不是 `Object`。

## 深入了解
- [返回结果](/docs/ui/navigation/returning-results) · [在界面之间导航](/docs/ui/navigation/navigate-between-screens)
- 姊妹篇：[打开和关闭一个界面](/docs/cookbook/nav/abrir-tela)
