# 如何创建货币字段

> 自动套用货币格式的字段：小数位数、千分位分隔，并可直接读回数值本身。

Source: https://crossfly.dev/zh/docs/cookbook/forms/mascara-moeda — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# 如何创建货币字段

**用途。** 创建一个从右向左格式化货币值的字段（用户输入 `12345` 并看到 `123,45`），根据 locale 进行千位分组和小数位处理，并把值作为十进制数取回用于计算。

## 用到的 API
- `campo.setMode(EditMode.CURRENCY, true)` — 开启带 `maskedEdit` 的货币模式。自动推导：`validChars = "0123456789.+-"`、`textAlignment = END`（右对齐）、`keyboard = CALCULATOR`，若没有掩码则 `mask = TextField.getDefaultCurrencyMask(decimalPlaces)`。
- `campo.<TextFieldStyle>getStyle().decimalPlaces(2)` — 小数位数（默认 `2`）。请在 `setMode` **之前**设置，因为默认掩码是根据它构建的。
- `TextField.getDefaultCurrencyMask(int decimalPlaces)` — 使用 `LocaleFormats.thousandsSeparator` 和 `LocaleFormats.decimalSeparator` 生成默认掩码（例如 pt-BR 中的 `999.999.999,99`）。
- `TextField.getText()` — 用于显示的格式化值（`"1.234,56"`）。
- `TextField.getTextWithoutMask()` — 带小数点的值，可直接用于 `Double.parseDouble`（`"1234.56"`）。会保留负号。

> 负号：在带掩码的货币模式下，输入 `-` 或 `+` 会切换符号而不插入字符（`handleCharInput`）。负号会在 `getTextWithoutMask()` 中作为前缀 `-` 出现。

> 分隔符通过 `LocaleFormats`（在初始化时填充）来自 locale。不要在代码中硬编码 `,`/`.`——使用 `getDefaultCurrencyMask` 或 `setMode(CURRENCY, true)` 以尊重地区设置。

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

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.style.*;   // TextFieldStyle（在样式中配置）

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

      TextField valor = new TextField("");
      valor.caption("Valor");
      valor.<TextFieldStyle>getStyle().decimalPlaces(2); // 在 setMode 之前设置
      valor.setMode(EditMode.CURRENCY, true);            // 货币 + 掩码 + 计算器键盘
      valor.setText("1234.56");                          // 显示 "1.234,56"（pt-BR）

      Label resultado = new Label("");

      Button somar = new Button("Somar 10");
      somar.onAction(o ->
      {
         double v = Double.parseDouble(valor.getTextWithoutMask()); // 1234.56
         double total = v + 10;
         resultado.setText("Total: " + total);
      });

      add(LAY_FILL, valor);
      add(LAY_AUTO, somar);
      add(LAY_FILL, resultado);
   }
}
```

> 下面的片段只展示**核心部分**。要运行它，请将其放入上面的 `MainWindow` 骨架中。

## 最小片段
```java
import dev.crossfly.ui.*;
import dev.crossfly.ui.style.*;
import static dev.crossfly.ui.UIConstants.EditMode;

TextField valor = new TextField("");
valor.caption("Valor");
valor.<TextFieldStyle>getStyle().decimalPlaces(2); // 在 setMode 之前设置
valor.setMode(EditMode.CURRENCY, true);            // 货币 + 掩码 + 计算器键盘

// 初始值：
valor.setText("1234.56"); // 显示 "1.234,56"（pt-BR）

Button somar = new Button("Somar");
somar.onAction(o ->
{
   double v = Double.parseDouble(valor.getTextWithoutMask()); // 1234.56
   // ... 计算
});
```

要使用自定义掩码（例如显式的 3 位小数）：
```java
valor.<TextFieldStyle>getStyle()
   .mask(TextField.getDefaultCurrencyMask(3)); // 之后 setMode(CURRENCY, true)
```

## 深入了解
- [掩码与键盘](/docs/ui/forms-and-input/masks-and-keyboards) · [文本字段](/docs/ui/forms-and-input/text-fields)
- 姊妹配方：[CPF/CEP/日期掩码](/docs/cookbook/forms/mascara-cpf) · [数字键盘](/docs/cookbook/forms/teclado-numerico)
- 权威来源：第 14 章 — 基础控件 · [枚举 (UIConstants)](/docs/reference/enums-uiconstants)
