# BarcodePicker

> Leitura de códigos de barras/QR pela câmera (classe abstrata).

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

# BarcodePicker

`BarcodePicker` lê **códigos de barras/QR** a partir de frames da câmera ao vivo, filtrando por formato. É uma **classe abstrata**: o consumidor implementa `onBarcode(BarcodeFormat format, String code)`. Segue o padrão dos pickers (ver [`Picker`](/docs/ui/widgets/picker)) — devolve o payload lido via `getAnswer()`.

> 🔴 · **Pacote:** `dev.crossfly.ui.picker` · **Estende:** `Picker implements GdxCamera.Listener` (abstrata) · **Hardware:** câmera

> ℹ️ Este `BarcodePicker` é a **leitura por câmera** e continua existindo. Não confundir com o antigo utilitário de *geração* de barcode (`util/barcode`), que foi removido na modernização.

## Quando usar
- Escanear códigos de barras (produtos, ingressos) ou QR codes.

## Quando NÃO usar
- Tirar foto/gravar vídeo → use [`PhotoPicker`](/docs/ui/widgets/photopicker).

## Aparência
Preview de câmera em tela cheia (fundo preto), título no topo, um **crosshair vermelho** central de mira e um "X" branco de fechar no canto inferior-direito.

## Exemplo completo (copiar, colar e rodar)
`BarcodePicker` é **abstrato**: instancie-o com um corpo que implemente `onBarcode`. Como é um overlay de câmera, dispare-o a partir de um `Button`. O exemplo reutiliza o uso básico (formatos 1D, fecha na 1ª leitura) e escreve o payload num `Label`. `BarcodeFormat` vem de `com.google.zxing`.

```java
package com.exemplo;

import com.google.zxing.BarcodeFormat;

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

      Label saida = new Label("Nenhum código lido");
      add(LAY_AUTO, saida);

      Button escanear = new Button("Escanear código")
         .onAction(c ->
         {
            BarcodePicker scanner = new BarcodePicker("Aponte para o código", BarcodePicker.formats1D)
            {
               protected void onBarcode(BarcodeFormat format, String code)
               {
                  onUI(() -> saida.setText(format + ": " + code)); // volta à paint thread
                  hide(); // fecha após a 1ª leitura (não fecha sozinho)
               }
            };
            scanner.show(answer -> {});
         });
      add(LAY_AUTO, escanear);
   }
}
```

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

## Uso básico
```java
BarcodePicker scanner = new BarcodePicker("Aponte para o código", BarcodePicker.formats1D)
{
   protected void onBarcode(BarcodeFormat format, String code)
   {
      Debug.log(format + ": " + code);
      hide(); // fecha após a 1ª leitura
   }
};
scanner.show(answer -> campoCodigo.setText((String) answer));
```

## Construtores
| Construtor | Descrição |
|---|---|
| `BarcodePicker(String title, BarcodeFormat... formats)` | Título + formatos aceitos (varargs; vazio = todos). Abstrato — instancie com corpo implementando `onBarcode`. |

## Propriedades e personalização
| Membro | Tipo | Default | O que faz |
|---|---|---|---|
| `BarcodePicker.formats1D` (estático) | `BarcodeFormat[]` | — | Conjunto pronto de formatos 1D (CODE_128, EAN_13…). |
| `BarcodePicker.formats2D` (estático) | `BarcodeFormat[]` | — | Conjunto pronto de formatos 2D (QR_CODE). |
| `BarcodePicker.beep` (estático) | `boolean` | `true` | Bipa ao decodificar. |
| `BarcodePicker.vibrate` (estático) | `boolean` | `true` | Vibra ao decodificar. |

## Callbacks e eventos
| Callback | Quando dispara |
|---|---|
| `onBarcode(BarcodeFormat, String)` | (abstrato) ao decodificar um código do formato aceito. |
| `show(onAnswer)` | ao fechar, entrega a `String` do último payload lido. |

`getAnswer()` retorna o último payload decodificado, ou `null` se cancelado.

## Estados
- **Não há `hide()` automático ao detectar** — quem decide fechar é a sua `onBarcode` (chamando `hide()`). Sem isso, o scanner continua lendo (útil para leitura contínua).
- Códigos repetidos consecutivos (mesmo `lastCode`) são ignorados.
- `onAppPause`/`onAppResume` gerenciam a câmera; `onRemove` para a thread de decodificação.

### Aceitar apenas QR e fechar na primeira leitura
```java
BarcodePicker scanner = new BarcodePicker("Leia o QR", BarcodePicker.formats2D)
{
   protected void onBarcode(BarcodeFormat format, String code)
   {
      onUI(() -> campoCodigo.setText(code)); // atualização de UI na paint thread
      hide();
   }
};
scanner.show(answer -> Debug.log("Lido: " + answer));
```

## Boas práticas
- Chame `hide()` em `onBarcode` para leitura única; omita para leitura contínua.
- A decodificação roda em thread de fundo — envolva atualizações de UI em `onUI(...)`.

## Erros comuns
- **Esquecer `hide()`** quando queria leitura única — o scanner continua ativo.
- **Atualizar UI direto na `onBarcode`** — respeite a paint thread com `onUI(...)`.

## Veja também
- Guia da área: [`ui/`](/docs/ui) · Receitas: [`cookbook/`](/docs/cookbook)
- Base do padrão: [`Picker`](/docs/ui/widgets/picker)
- Componentes relacionados: [`PhotoPicker`](/docs/ui/widgets/photopicker)
