# Picker (classe base)

> Base de todos os pickers — o padrão getAnswer() + show(onAnswer).

Source: https://crossfly.dev/pt/docs/ui/widgets/picker — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Picker (classe base)

`Picker` é a base comum de todas as janelas de seleção do CrossFly (data, hora, arquivo, foto, cor, código de barras, coordenada). Cada picker abre, deixa o usuário interagir e, ao **confirmar**, fecha-se sozinho entregando o resultado de forma assíncrona, via callback, ao código que o abriu.

Entender o padrão desta página é entender **todos** os pickers de uma vez.

> 🟡 · **Pacote:** `dev.crossfly.ui.picker` · **Estende:** `Window` · **Transição:** `FADE` por padrão

## O padrão central: `getAnswer()` + `show(onAnswer)`

- **`Picker.getAnswer()`** produz o valor selecionado (cada subclasse sobrescreve para devolver o tipo concreto: `String`, `Integer`, `LatLon`…). Na base, retorna `null`.
- **`Window.show(RunnableWith<Object> onAnswer)`** consome esse valor **quando a janela é fechada**.

O elo entre os dois está em `Window.hide()`:

```java
public void hide() {
   ...
   Object answer = this instanceof Picker ? ((Picker) this).getAnswer() : null;
   if (onAnswer != null && answer != null)
      onAnswer.run(answer);
   ...
}
```

Consequências práticas (todas confirmadas no código):

- **O callback `onAnswer` só dispara em `hide()` e somente se `getAnswer() != null`.** Ao **cancelar**, as subclasses fazem `getAnswer()` retornar `null` — então o `onAnswer` **não** é chamado. Quem precisa reagir ao cancelamento deve sobrescrever `onHide()`/`onRemove()` ou usar o callback específico da subclasse.
- `show(onAnswer)` é **thread-safe**: se chamado fora da paint thread, é reagendado e bloqueia até concluir.
- O valor entregue é `Object`; o consumidor faz **cast** para o tipo concreto do picker.

> Isto contrasta com [`Alert`](/docs/ui/widgets/alert)/[`ActionSheet`](/docs/ui/widgets/actionsheet), que estendem `Window` mas **não** `Picker` — neles `show(onAnswer)` não dispara e a resposta vem por callbacks de botão.

## Exemplo completo (copiar, colar e rodar)
```java
package com.exemplo;

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

/** Tela principal executável. Aponte o launcher (classname) e rode: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      Button abrir = new Button("Abrir picker");
      abrir.onAction(c ->
      {
         // Qualquer subclasse de Picker segue o mesmo padrão show(onAnswer)
         DatePicker dp = new DatePicker();
         dp.show(answer ->
         {
            // 'answer' é o Object devolvido por getAnswer(); só chega aqui se != null
            String data = (String) answer;
            Hint.show("Selecionado: " + data, 2000);
         });
      });
      add(LAY_AUTO, abrir);
   }
}
```

> Os trechos abaixo mostram **só o miolo** (o que vai dentro de `onShow()`). Para rodar, coloque-os no esqueleto `MainWindow` acima.

## Uso básico (forma genérica de qualquer picker)
```java
DatePicker dp = new DatePicker();
dp.show(answer ->
{
   // 'answer' é o Object devolvido por getAnswer(); só chega aqui se != null
   String data = (String) answer;
   Debug.log("Selecionado: " + data);
});
```

## Métodos públicos
| Método | Retorno | Descrição |
|---|---|---|
| `getAnswer()` | `Object` | Resultado do picker, ou `null` se cancelado. Sobrescrito por cada subclasse. |
| `show(RunnableWith<Object> onAnswer)` | `void` | Abre o picker; entrega o valor via callback ao fechar (herdado de `Window`). |

## Tipos devolvidos por subclasse
| Picker | `getAnswer()` devolve |
|---|---|
| [`DatePicker`](/docs/ui/widgets/datepicker) | `String` (data conforme `LocaleFormats.dateFormat`/`dateSeparator`) |
| [`TimePicker`](/docs/ui/widgets/timepicker) | `String` (`HH:MM`, 24h) |
| [`FilePicker`](/docs/ui/widgets/filepicker) | — (esqueleto vazio; herda `null` da base) |
| [`PhotoPicker`](/docs/ui/widgets/photopicker) | `String` (caminho **ou** `"ERROR: ..."`) |
| [`ColorPicker`](/docs/ui/widgets/colorpicker) | `Integer` (RGB sem alpha) |
| [`BarcodePicker`](/docs/ui/widgets/barcodepicker) | `String` (payload lido) |
| [`LocationPicker`](/docs/ui/widgets/locationpicker) | `LatLon` |

## Boas práticas
- Sempre faça o **cast** do `Object` para o tipo concreto da tabela acima.
- Para reagir ao cancelamento, não conte com `onAnswer` — use o callback específico (`onSelect`/`onCapture`) ou sobrescreva `onHide()`.
- Pickers de hardware (`PhotoPicker`, `BarcodePicker`, `LocationPicker`) liberam recursos ao fechar; não reaproveite a mesma instância após `hide()`.

## Erros comuns
- **Esperar `onAnswer` no cancelamento** — não dispara, porque `getAnswer()` devolve `null`.
- **Esquecer o cast** — o callback recebe `Object`.

## Veja também
- Guia da área: [`ui/`](/docs/ui) · Receitas: [`cookbook/`](/docs/cookbook)
- Subclasses: [`DatePicker`](/docs/ui/widgets/datepicker) · [`TimePicker`](/docs/ui/widgets/timepicker) · [`FilePicker`](/docs/ui/widgets/filepicker) · [`PhotoPicker`](/docs/ui/widgets/photopicker) · [`ColorPicker`](/docs/ui/widgets/colorpicker) · [`BarcodePicker`](/docs/ui/widgets/barcodepicker) · [`LocationPicker`](/docs/ui/widgets/locationpicker)
