# Como usar checkbox e radio (Option e Group)

> Um Option sozinho vira checkbox; vários em um Group viram radio (seleção exclusiva).

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

# Como usar checkbox e radio (Option e Group)

**Propósito.** Oferecer opções marcáveis. Um `Option` isolado funciona como **checkbox**
(liga/desliga independente). Vários `Option` no mesmo `Group` funcionam como **radio
buttons** (apenas um marcado por vez). Use checkbox para escolhas independentes; radio
para escolha única entre alternativas.

## APIs usadas
- `new Option()` / `new Option(String text)` — cria a opção (com ou sem rótulo). Começa desmarcada.
- `option.checked(boolean checked)` — define o estado inicial **sem animação** (fluente).
- `option.setChecked(boolean checked)` — muda o estado **com animação** de crossfade.
- `option.isChecked()` — retorna o estado atual (`boolean`).
- `option.toggle()` — inverte o estado (chamado internamente no toque).
- `option.onAction(Component.Action action)` — callback disparado **quando o estado muda** por toque do usuário.
- `new Group()` — grupo de seleção mutuamente exclusiva.
- `option.group(Group g)` — associa a opção ao grupo (transforma em radio).
- `group.fade(boolean)` — habilita transição animada de cor ao trocar a seleção.

> Comportamento não óbvio (confirmado na fonte):
> - Em um `Group`, tocar na opção **já marcada** não a desmarca (`toggle()` retorna cedo
>   se `checked && getGroup() != null`) — igual ao rádio: só troca ao escolher outra.
> - `onAction` só dispara se o estado realmente mudou (`if (checked != prev) runActions()`).
> - Marcar via `checked(true)` numa opção de grupo já notifica o grupo e desmarca as demais.

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

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

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

      // ── Checkbox (Option isolado) ──
      Option aceito = new Option("Aceito os termos");
      aceito.checked(false);                 // estado inicial, sem animação
      aceito.onAction(o -> atualizarBotao(aceito.isChecked()));
      add(aceito);

      // ── Radio (vários Option no mesmo 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);                  // seleção inicial do grupo

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

      add(padrao);
      add(expresso);
   }

   private void atualizarBotao(boolean aceito)
   {
      // ... habilitar/desabilitar o botão conforme o checkbox ...
   }

   private void escolherFrete(String tipo)
   {
      // ... reagir à escolha do frete ...
   }
}
```

> O trecho abaixo mostra **só o miolo**. Para rodar, coloque-o no esqueleto `MainWindow` acima.

## Trecho mínimo
```java
// ── Checkbox (Option isolado) ──
Option aceito = new Option("Aceito os termos");
aceito.checked(false);                 // estado inicial, sem animação
aceito.onAction(o -> atualizarBotao(aceito.isChecked()));
add(aceito);

// ── Radio (vários Option no mesmo 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);                  // seleção inicial do grupo

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

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

> **Nota de verificação (código 2026).** Confirmado: `Option` implementa `Component.Checkable`
> e `AlphaAnimation.Animate`; `Group.select(sender)` desmarca os demais membros
> (`Option`/`Switch`) automaticamente. `Group.fade` (default `false`) controla se a
> troca é animada. Não há "valor" no `Group`: para saber a seleção, verifique
> `isChecked()` em cada `Option`, ou guarde a referência escolhida no callback.

## Aprofunde-se
- Páginas dos widgets: [Option](/docs/ui/widgets/option) · [Group](/docs/ui/widgets/group)
- Dropdown (seleção única em popup): [dropdown-selecao.md](/docs/cookbook/ui/dropdown-selecao)
