# Group

> 使 Options/Switches 互斥（单选按钮）的逻辑注册表。

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

# Group

`Group` 将"可勾选"组件（[`option`](/docs/ui/widgets/option)、[`switch`](/docs/ui/widgets/switch) 以及任何 `Checkable`）分组，以实现**互斥选择** —— 即单选按钮的行为。当某个成员被勾选时，其余成员会自动取消勾选，可选择带有动画过渡（fade）。它不是 `Component`：**它不绘制任何内容**，仅仅是成员注册表 + 互斥逻辑。

> 🟢 · **包：** `dev.crossfly.ui` · **继承：** `java.lang.Object`（非可视） · **样式：** —（无自身样式）

## 何时使用
- 将一组 [`option`](/docs/ui/widgets/option) 转变为互斥的单选按钮。
- 使一组 [`switch`](/docs/ui/widgets/switch) 或你自己的任何 `Checkable` 互斥。

## 何时不要使用
- 对于单个开关切换 → [`switch`](/docs/ui/widgets/switch) 或不带分组的 [`option`](/docs/ui/widgets/option) 就足够了。

## 外观
无。`Group` 纯粹是逻辑性的。每个按钮的外观由成员负责（这些成员需要是可勾选的可视组件）。

## 完整示例（复制、粘贴并运行）
```java
package com.exemplo;

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

/** 可执行的主界面。将 launcher 指向此类（classname）并运行：gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      Label saida = new Label("Selecionado: Cartão");
      add(LAY_AUTO, saida);

      // Group 使各 Option 互斥（单选），切换时带淡入淡出
      Group g = new Group().fade(true);

      Option[] ops = {
         new Option("Cartão").group(g).checked(true),
         new Option("Boleto").group(g),
         new Option("Pix").group(g)
      };

      for (Option o : ops)
      {
         // Group 不保存选中项：每个成员通知，我们读取 isChecked()
         o.onAction(c -> {
            for (Option x : ops)
               if (x.isChecked())
                  saida.setText("Selecionado: " + x.text);
         });
         add(LAY_AUTO, o);
      }
   }
}
```

> 下面的片段只展示**核心部分**（放入 `onShow()` 内的内容）。要运行它们，请将其放入上面的 `MainWindow` 骨架中。

## 基本用法
```java
Group g = new Group().fade(true);                       // fade = 动画过渡

Option a = new Option("Opção A").group(g);
Option b = new Option("Opção B").group(g);
Option c = new Option("Opção C").group(g);

container.add(LAY_AUTO, a);
container.add(LAY_AUTO, b);
container.add(LAY_AUTO, c);
// 选中任意一个时，其余的以淡出取消选中。
```

## 构造函数
| 构造函数 | 描述 |
|---|---|
| `Group()` | 空分组，无 fade。 |

## 属性与自定义
| 属性 / 方法 | 类型 | 默认值 | 作用 |
|---|---|---|---|
| `fade(boolean)` | `Group`（链式） | `false` | 开启/关闭选择的动画过渡。 |
| `fade` | `boolean`（字段） | `false` | fade 状态（读取）。 |
| `add(Component)` | `void` | — | 注册一个成员（按身份忽略重复项）。 |
| `remove(Component)` | `void` | — | 移除一个成员（若不是成员则为空操作）。 |
| `select(Component sender)` | `void` | — | 取消勾选**除** `sender` **以外**的所有成员。 |

> 通常你**不需要**直接调用 `add`/`select`：可勾选组件本身会通过 `.group(group)` 自行注册，并在被勾选时调用 `select(this)`。

## 回调与事件
`Group` 没有回调。请在每个成员的 `onAction` 中响应变化，并查询 `isChecked()`。

## 状态
`Group` 不保存"哪个被选中" —— 它仅确保当有人通知其被勾选时，其余成员被关闭。**没有 `getSelected()`**：请在每个成员上查询其状态（`isChecked()`）。

### 找出哪个成员被选中
```java
Group g = new Group();
Option[] ops = {
   new Option("Cartão").group(g).checked(true),
   new Option("Boleto").group(g),
   new Option("Pix").group(g)
};
for (Option o : ops)
   container.add(LAY_AUTO, o);

// 在某处（例如："确认" 按钮）：
for (Option o : ops)
   if (o.isChecked())
      System.out.println("selecionado: " + o.text);
```

## 最佳实践
- 让注册由组件自己完成：`.group(g)` 内部已经调用了 `group.add(this)`。
- 互斥性之所以有效，是因为 `Option`/`Switch` 在被勾选时会调用 `select(this)`；你自己的 `Checkable` 也需要这样做。

## 常见错误
- 寻找不存在的 `getSelected()` —— 请遍历成员并查询 `isChecked()`。
- 在某个成员上忘记 `.group(g)`：它将被排除在互斥之外。

## 另请参阅
- 领域指南：[`ui/`](/docs/ui) · 食谱：[`cookbook/`](/docs/cookbook)
- 概念（组件组合）：[`concepts/`](/docs/concepts)
- 相关组件：[`option`](/docs/ui/widgets/option) · [`switch`](/docs/ui/widgets/switch)
