# 文本字段

> TextField——浮动标题、图标、带切换的密码框以及读取值。

Source: https://crossfly.dev/zh/docs/ui/forms-and-input/text-fields — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# 文本字段（`TextField`）

`TextField` 是**单行**字段。基础功能使用流式 API；精细行为来自
`TextFieldStyle`。

## 完整示例（复制、粘贴并运行）
```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 nome = new TextField().caption("Nome");
      nome.<TextFieldStyle>getStyle().floatingCaption(true);
      add(LAY_AUTO, nome);

      // 带显示/隐藏按钮的密码字段
      TextField senha = new TextField().caption("Senha");
      senha.<TextFieldStyle>getStyle()
         .mode(EditMode.PASSWORD)
         .passwordToggle(true);
      add(LAY_AUTO, senha);

      // 用于显示读取值的标签
      Label resultado = new Label("");
      add(LAY_AUTO, resultado);

      // 没有按键回调：在提交时读取 getText()
      Button enviar = new Button("Enviar");
      enviar.onAction(c -> resultado.setText("Nome = " + nome.getText()));
      add(LAY_AUTO, enviar);
   }
}
```

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

## 基本用法
```java
TextField nome = new TextField()
   .caption("Nome")                 // 浮动标签
   .text("");                       // 初始值
painel.add(LAY_AUTO, nome);

// 需要时读取值（没有按键事件）：
Button enviar = new Button("Enviar");
enviar.onAction(c -> Debug.log("Nome = " + nome.getText()));
```

## 构造函数与流式 API
| 成员 | 效果 |
|---|---|
| `new TextField()` / `new TextField("texto")` | 空字段 / 带初始值 |
| `.caption(String)` | 标题（若启用 `floatingCaption`，聚焦时浮动） |
| `.text(String)` / `setText(String)` | 设置值 |
| `.leftIcon(Icon)` / `.rightIcon(Icon)` | 两端的图标 |
| `.rightIcon(Icon, Action)` | 可点击图标（如清空） |
| `.keyboard(Keyboard)` | 键盘类型（参见[掩码与键盘](/docs/ui/forms-and-input/masks-and-keyboards)） |
| `getText()` / `getTextWithoutMask()` | 读取值（带 / 不带掩码） |
| `clearText()` | 清空 |

## 浮动标题
在样式中启用（`floatingCaption`）——标题在聚焦/填写时上移：
```java
TextField email = new TextField().caption("E-mail");
email.<TextFieldStyle>getStyle().floatingCaption(true);
```

## 带显示/隐藏按钮的密码框
```java
TextField senha = new TextField().caption("Senha");
senha.<TextFieldStyle>getStyle()
   .mode(EditMode.PASSWORD)     // 遮蔽字符
   .passwordToggle(true);       // 自动添加眼睛图标
```
使用 `passwordToggle(true)` 时，右侧图标会自动切换可见性。

## 操作图标（如清空）
```java
TextField busca = new TextField().caption("Buscar")
   .rightIcon(new MaterialIcon(""), c -> busca.clearText());  // "close"
```

## 最佳实践
- 在提交时用 `getText()` 读取值；对于原始数字，使用 `getTextWithoutMask()`。
- 通过类型化的 `getStyle()`（`campo.<TextFieldStyle>getStyle()...`）配置行为
  （`mode`、`maxLength`、`floatingCaption`）。
- 在有意义时用样式中的 `.maxLength(n)` 限制长度。

## 常见错误
- 寻找 `onChange`/`onTextChanged`——**它不存在**；需要时读取 `getText()`。
- 在保存到数据库时混淆 `getText()`（带掩码）和 `getTextWithoutMask()`（不带掩码）。
- 在组件上设置 `mode`/`mask`——它们是**样式**的 setter。

## 另见
- [掩码与键盘](/docs/ui/forms-and-input/masks-and-keyboards) · [焦点与验证](/docs/ui/forms-and-input/focus-and-validation) · [文本区域](/docs/ui/forms-and-input/text-areas)
- 目录：[TextField](/docs/ui/widgets/textfield) · 参考：第 14 章
