# Cómo usar checkbox y radio (Option y Group)

> Un Option solo se convierte en checkbox; varios en un Group se convierten en radio (selección exclusiva).

Source: https://crossfly.dev/es/docs/cookbook/ui/checkbox-e-radio — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Cómo usar checkbox y radio (Option y Group)

**Propósito.** Ofrecer opciones marcables. Un `Option` aislado funciona como **checkbox**
(activa/desactiva independiente). Varios `Option` en el mismo `Group` funcionan como **radio
buttons** (solo uno marcado a la vez). Usa checkbox para elecciones independientes; radio
para una elección única entre alternativas.

## APIs usadas
- `new Option()` / `new Option(String text)` — crea la opción (con o sin etiqueta). Empieza desmarcada.
- `option.checked(boolean checked)` — define el estado inicial **sin animación** (fluido).
- `option.setChecked(boolean checked)` — cambia el estado **con animación** de crossfade.
- `option.isChecked()` — devuelve el estado actual (`boolean`).
- `option.toggle()` — invierte el estado (invocado internamente al toque).
- `option.onAction(Component.Action action)` — callback disparado **cuando el estado cambia** por toque del usuario.
- `new Group()` — grupo de selección mutuamente exclusiva.
- `option.group(Group g)` — asocia la opción al grupo (la transforma en radio).
- `group.fade(boolean)` — habilita la transición animada de color al cambiar la selección.

> Comportamiento no obvio (confirmado en la fuente):
> - En un `Group`, tocar la opción **ya marcada** no la desmarca (`toggle()` retorna temprano
>   si `checked && getGroup() != null`) — igual que el radio: solo cambia al elegir otra.
> - `onAction` solo se dispara si el estado realmente cambió (`if (checked != prev) runActions()`).
> - Marcar mediante `checked(true)` en una opción de grupo ya notifica al grupo y desmarca las demás.

## Ejemplo completo (copiar, pegar y ejecutar)
```java
package com.exemplo;

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

/** Pantalla principal ejecutable. Apunta el launcher (classname) y corre: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      // ── Checkbox (Option aislado) ──
      Option aceito = new Option("Aceito os termos");
      aceito.checked(false);                 // estado inicial, sin animación
      aceito.onAction(o -> atualizarBotao(aceito.isChecked()));
      add(aceito);

      // ── Radio (varios Option en el mismo Group) ──
      Group entrega = new Group();

      Option padrao   = new Option("Entrega padrão").group(entrega);
      Option expresso = new Option("Entrega expressa").group(entrega);

      padrao.checked(true);                  // selección inicial del grupo

      expresso.onAction(o -> escolherFrete("EXPRESSO"));
      padrao.onAction(o -> escolherFrete("PADRAO"));

      add(padrao);
      add(expresso);
   }

   private void atualizarBotao(boolean aceito)
   {
      // ... habilitar/deshabilitar el botón según el checkbox ...
   }

   private void escolherFrete(String tipo)
   {
      // ... reaccionar a la elección del envío ...
   }
}
```

> El fragmento de abajo muestra **solo el núcleo**. Para ejecutarlo, colócalo en el esqueleto `MainWindow` de arriba.

## Fragmento mínimo
```java
// ── Checkbox (Option aislado) ──
Option aceito = new Option("Aceito os termos");
aceito.checked(false);                 // estado inicial, sin animación
aceito.onAction(o -> atualizarBotao(aceito.isChecked()));
add(aceito);

// ── Radio (varios Option en el mismo Group) ──
Group entrega = new Group();

Option padrao  = new Option("Entrega padrão").group(entrega);
Option expresso = new Option("Entrega expressa").group(entrega);

padrao.checked(true);                  // selección inicial del grupo

expresso.onAction(o -> escolherFrete("EXPRESSO"));
padrao.onAction(o -> escolherFrete("PADRAO"));

add(padrao);
add(expresso);
```

> **Nota de verificación (código 2026).** Confirmado: `Option` implementa `Component.Checkable`
> y `AlphaAnimation.Animate`; `Group.select(sender)` desmarca a los demás miembros
> (`Option`/`Switch`) automáticamente. `Group.fade` (por defecto `false`) controla si el
> cambio es animado. No hay "valor" en el `Group`: para conocer la selección, verifica
> `isChecked()` en cada `Option`, o guarda la referencia elegida en el callback.

## Profundiza
- Páginas de los widgets: [Option](/docs/ui/widgets/option) · [Group](/docs/ui/widgets/group)
- Dropdown (selección única en popup): [dropdown-selecao.md](/docs/cookbook/ui/dropdown-selecao)
