# BarcodePicker

> Reading barcodes/QR codes with the camera (abstract class).

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

# BarcodePicker

`BarcodePicker` reads **barcodes/QR codes** from live camera frames, filtering by format. It is an **abstract class**: the consumer implements `onBarcode(BarcodeFormat format, String code)`. It follows the picker pattern (see [`Picker`](/docs/ui/widgets/picker)) — it returns the read payload via `getAnswer()`.

> 🔴 · **Package:** `dev.crossfly.ui.picker` · **Extends:** `Picker implements GdxCamera.Listener` (abstract) · **Hardware:** camera

> ℹ️ This `BarcodePicker` is the **camera-based reader** and still exists. Do not confuse it with the old barcode *generation* utility (`util/barcode`), which was removed during modernization.

## When to use
- Scan barcodes (products, tickets) or QR codes.

## When NOT to use
- Take a photo/record video → use [`PhotoPicker`](/docs/ui/widgets/photopicker).

## Appearance
Full-screen camera preview (black background), title at the top, a central red **crosshair** for aiming, and a white "X" close button in the bottom-right corner.

## Complete example (copy, paste and run)
`BarcodePicker` is **abstract**: instantiate it with a body implementing `onBarcode`. Since it is a camera overlay, trigger it from a `Button`. The example reuses the basic usage (1D formats, closes on the 1st read) and writes the payload into a `Label`. `BarcodeFormat` comes from `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.*;

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

      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)); // back to the paint thread
                  hide(); // closes after the 1st read (doesn't close on its own)
               }
            };
            scanner.show(answer -> {});
         });
      add(LAY_AUTO, escanear);
   }
}
```

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

## Basic usage
```java
BarcodePicker scanner = new BarcodePicker("Aponte para o código", BarcodePicker.formats1D)
{
   protected void onBarcode(BarcodeFormat format, String code)
   {
      Debug.log(format + ": " + code);
      hide(); // closes after the 1st read
   }
};
scanner.show(answer -> campoCodigo.setText((String) answer));
```

## Constructors
| Constructor | Description |
|---|---|
| `BarcodePicker(String title, BarcodeFormat... formats)` | Title + accepted formats (varargs; empty = all). Abstract — instantiate with a body implementing `onBarcode`. |

## Properties and customization
| Member | Type | Default | What it does |
|---|---|---|---|
| `BarcodePicker.formats1D` (static) | `BarcodeFormat[]` | — | Ready-made set of 1D formats (CODE_128, EAN_13…). |
| `BarcodePicker.formats2D` (static) | `BarcodeFormat[]` | — | Ready-made set of 2D formats (QR_CODE). |
| `BarcodePicker.beep` (static) | `boolean` | `true` | Beeps on decoding. |
| `BarcodePicker.vibrate` (static) | `boolean` | `true` | Vibrates on decoding. |

## Callbacks and events
| Callback | When it fires |
|---|---|
| `onBarcode(BarcodeFormat, String)` | (abstract) on decoding a code of an accepted format. |
| `show(onAnswer)` | on close, delivers the `String` of the last read payload. |

`getAnswer()` returns the last decoded payload, or `null` if canceled.

## States
- **There is no automatic `hide()` on detection** — you decide when to close in your `onBarcode` (by calling `hide()`). Without it, the scanner keeps reading (useful for continuous reading).
- Consecutive repeated codes (same `lastCode`) are ignored.
- `onAppPause`/`onAppResume` manage the camera; `onRemove` stops the decoding thread.

### Accept only QR and close on the first read
```java
BarcodePicker scanner = new BarcodePicker("Leia o QR", BarcodePicker.formats2D)
{
   protected void onBarcode(BarcodeFormat format, String code)
   {
      onUI(() -> campoCodigo.setText(code)); // UI update on the paint thread
      hide();
   }
};
scanner.show(answer -> Debug.log("Lido: " + answer));
```

## Best practices
- Call `hide()` in `onBarcode` for a single read; omit it for continuous reading.
- Decoding runs on a background thread — wrap UI updates in `onUI(...)`.

## Common mistakes
- **Forgetting `hide()`** when you wanted a single read — the scanner stays active.
- **Updating the UI directly in `onBarcode`** — respect the paint thread with `onUI(...)`.

## See also
- Area guide: [`ui/`](/docs/ui) · Recipes: [`cookbook/`](/docs/cookbook)
- Pattern base: [`Picker`](/docs/ui/widgets/picker)
- Related components: [`PhotoPicker`](/docs/ui/widgets/photopicker)
