# Picker (base class)

> Base of all pickers — the getAnswer() + show(onAnswer) pattern.

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

# Picker (base class)

`Picker` is the common base of all CrossFly selection windows (date, time, file, photo, color, barcode, coordinate). Each picker opens, lets the user interact and, upon **confirming**, closes itself, delivering the result asynchronously, via callback, to the code that opened it.

Understanding the pattern on this page means understanding **all** pickers at once.

> 🟡 · **Package:** `dev.crossfly.ui.picker` · **Extends:** `Window` · **Transition:** `FADE` by default

## The central pattern: `getAnswer()` + `show(onAnswer)`

- **`Picker.getAnswer()`** produces the selected value (each subclass overrides it to return the concrete type: `String`, `Integer`, `LatLon`…). In the base, it returns `null`.
- **`Window.show(RunnableWith<Object> onAnswer)`** consumes that value **when the window is closed**.

The link between the two lies in `Window.hide()`:

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

Practical consequences (all confirmed in the code):

- **The `onAnswer` callback only fires in `hide()` and only if `getAnswer() != null`.** When **canceling**, subclasses make `getAnswer()` return `null` — so `onAnswer` is **not** called. Anyone who needs to react to the cancellation must override `onHide()`/`onRemove()` or use the subclass-specific callback.
- `show(onAnswer)` is **thread-safe**: if called outside the paint thread, it is rescheduled and blocks until completed.
- The delivered value is `Object`; the consumer **casts** it to the picker's concrete type.

> This contrasts with [`Alert`](/docs/ui/widgets/alert)/[`ActionSheet`](/docs/ui/widgets/actionsheet), which extend `Window` but **not** `Picker` — in them `show(onAnswer)` does not fire and the response comes via button callbacks.

## Complete example (copy, paste and run)
```java
package com.exemplo;

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

/** 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());

      Button abrir = new Button("Abrir picker");
      abrir.onAction(c ->
      {
         // Any Picker subclass follows the same show(onAnswer) pattern
         DatePicker dp = new DatePicker();
         dp.show(answer ->
         {
            // 'answer' is the Object returned by getAnswer(); only reaches here if != null
            String data = (String) answer;
            Hint.show("Selecionado: " + data, 2000);
         });
      });
      add(LAY_AUTO, abrir);
   }
}
```

> The snippets below show **only the core** (what goes inside `onShow()`). To run them, place them in the `MainWindow` skeleton above.

## Basic usage (generic form of any picker)
```java
DatePicker dp = new DatePicker();
dp.show(answer ->
{
   // 'answer' is the Object returned by getAnswer(); only reaches here if != null
   String data = (String) answer;
   Debug.log("Selecionado: " + data);
});
```

## Public methods
| Method | Return | Description |
|---|---|---|
| `getAnswer()` | `Object` | Picker result, or `null` if canceled. Overridden by each subclass. |
| `show(RunnableWith<Object> onAnswer)` | `void` | Opens the picker; delivers the value via callback on close (inherited from `Window`). |

## Types returned by subclass
| Picker | `getAnswer()` returns |
|---|---|
| [`DatePicker`](/docs/ui/widgets/datepicker) | `String` (date per `LocaleFormats.dateFormat`/`dateSeparator`) |
| [`TimePicker`](/docs/ui/widgets/timepicker) | `String` (`HH:MM`, 24h) |
| [`FilePicker`](/docs/ui/widgets/filepicker) | — (empty skeleton; inherits `null` from the base) |
| [`PhotoPicker`](/docs/ui/widgets/photopicker) | `String` (path **or** `"ERROR: ..."`) |
| [`ColorPicker`](/docs/ui/widgets/colorpicker) | `Integer` (RGB without alpha) |
| [`BarcodePicker`](/docs/ui/widgets/barcodepicker) | `String` (payload read) |
| [`LocationPicker`](/docs/ui/widgets/locationpicker) | `LatLon` |

## Best practices
- Always **cast** the `Object` to the concrete type from the table above.
- To react to cancellation, do not rely on `onAnswer` — use the specific callback (`onSelect`/`onCapture`) or override `onHide()`.
- Hardware pickers (`PhotoPicker`, `BarcodePicker`, `LocationPicker`) release resources on close; do not reuse the same instance after `hide()`.

## Common mistakes
- **Expecting `onAnswer` on cancellation** — it does not fire, because `getAnswer()` returns `null`.
- **Forgetting the cast** — the callback receives `Object`.

## See also
- Area guide: [`ui/`](/docs/ui) · Recipes: [`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)
