前几篇把 TextField 的属性、校验、样式分头讲完了,这篇不碰新东西,把它们串起来做两个最常见的表单应用:搜索框自动补全、登录表单。
这篇是两个 demo:
- 自动关联 --- 输入时弹出匹配项,点一下自动填入
- 表单提交 --- 用户名/密码带图标,两个都填了登录按钮才亮
自动关联
先看搜索框的联想功能:你每敲一个字符,下面立刻弹出一串匹配项,点一下就填进输入框。整个交互牵扯四个组件:TextField 负责输入,Popup 负责弹层,ListView 展示结果,ItemDelegate 做可点击的候选行。

演示代码
源码里样式代码占了不少行,跟核心逻辑无关,这里全部折叠掉,只看三件事:怎么过滤、怎么弹出来、点完怎么填回去。
qml
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Layouts
FadeInAnimation {
property var keywords: ["a", "ab", "abc", "bcd", "bcde", "cdef", "cdefg", "cdefgh"]
property var matches: []
// ... 省略外层布局与标题组件 TitleSeparator ...
TextField {
id: autoCompleteField
placeholderText: "输入文本..."
// ... 背景样式省略 ...
onTextChanged: {
if (text.length > 0) {
matches = keywords.filter(function(key) {
return key.toLowerCase().indexOf(text.toLowerCase()) === 0
})
autoCompletePopup.visible = matches.length > 0
} else {
autoCompletePopup.visible = false
}
}
}
Popup {
id: autoCompletePopup
parent: autoCompleteField
y: parent.height + 5
width: parent.width
height: 180
contentItem: ListView {
model: matches
clip: true
delegate: ItemDelegate {
width: parent.width
height: 30
text: modelData
// ... 悬停配色省略 ...
onClicked: {
autoCompleteField.text = modelData
autoCompletePopup.visible = false
}
}
ScrollIndicator.vertical: ScrollIndicator {}
}
}
}
关键逻辑解析
整个自动补全交互流程可以串成一条链路:用户输入内容 → 过滤出匹配候选项 → 弹出下拉弹窗 → 点击候选项回填内容,拆开看每一步实现都不难。
过滤逻辑 写在 onTextChanged 里面。keywords 存放全部候选词,matches 保存筛选出来的结果。 调用 filter() 做前缀匹配,用 indexOf(...) === 0 判断开头是否吻合,再通过 toLowerCase() 忽略大小写,哪怕输入大写 CD,也能搜到小写的 cdef。 有匹配结果就显示弹窗,输入框清空就把弹窗隐藏。
弹窗最麻烦的是定位问题 。 Popup 如果不指定父组件 parent,会直接跑到窗口左上角,和输入框互不相关。我们把 parent 指定为输入框 autoCompleteField,将弹窗依附输入框;设置 y: parent.height + 5,弹窗就贴在输入框下方,宽度和输入框保持一致,看起来就是输入框自带的下拉面板。
点击选择回填交给 ListView 和 ItemDelegate 。 model 绑定过滤结果数组 matches,数组一变,列表会自动更新,不用手动写刷新逻辑。 每个候选项是一个 ItemDelegate,点击触发 onClicked,拿 modelData 回填到输入框文本,再关闭弹窗,补全就完成。 至于鼠标悬停时背景变色,只是在 delegate 的背景样式里判断 hovered 状态,属于UI体验优化,不改变核心业务逻辑。
适用场景
大多数的"边输边联想"的地方都能用:搜索框提示、邮箱后缀补全、标签输入、命令行补全。把 keywords 换成动态数据源,输入时请求一次后端接口,就是搜索引擎式的实时建议了。
表单提交
第二个场景是登录表单:用户名、密码各一个输入框,密码用圆点掩码显示,两个框都填了登录按钮才亮。前几篇的图标嵌入、密码模式、background 样式、属性绑定,这里一次性全用上。

演示代码
两个输入框结构完全一样,区别只有图标和密码模式,所以只贴用户名框,密码框的差异在注释里说明。
qml
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Layouts
FadeInAnimation {
// ... 省略外层布局与标题组件 TitleSeparator ...
TextField {
id: usernameField
placeholderText: "用户名"
leftPadding: 40 // 给左边图标留位置
verticalAlignment: Text.AlignVCenter
background: Rectangle {
color: "white"
border.color: usernameField.activeFocus ? "#2196F3" : "#BBDEFB"
border.width: usernameField.activeFocus ? 2 : 1
radius: 4
// 图标直接嵌在背景里,锚定在左侧
Image {
source: "/icons/user-icon.png"
anchors.left: parent.left
anchors.leftMargin: 10
anchors.verticalCenter: parent.verticalCenter
width: 20
height: 20
}
}
}
// passwordField 结构同上,只差两处:
// 1. 加 echoMode: TextField.Password 让输入显示为掩码
// 2. 图标换成 /icons/lock-icon.png
Button {
text: "登录"
enabled: usernameField.text !== "" && passwordField.text !== ""
// ... 背景三态样式省略 ...
onClicked: console.log("尝试登录:", usernameField.text)
}
}
关键逻辑解析
有两个地方值得拿出来说。
- 密码框 密码框关键就一行代码:
echoMode: TextField.Password,开启之后输入的字符就会变成圆点。再配上锁形图标,用户一看就知道这里要输密码。掩码 + 图标组合在一起,比只做其中一种提示要清晰直观。 - 登录按钮是这个 Demo 的核心,只用一行绑定就搞定状态控制:
vbnet
enabled: usernameField.text !== "" && passwordField.text !== ""
这就是声明式绑定的优势:不用自己写监听回调。只要用户名或者密码输入框内容改动,enabled 会自动重新计算,按钮能不能点的状态自动更新。
按钮背景做了三套样式:正常是蓝色、按下变深蓝、禁用显示浅蓝,依靠 parent.enabled 和 parent.pressed 的三元条件来切换。文字颜色也跟着启用状态联动,禁用的时候文字会变淡,让用户一眼就明白按钮现在无法点击。
适用场景
大多数"表单提交"的常规设计:登录、注册、搜索提交、设置保存。核心套路是"输入框 + 按钮 + enabled 联动",记住这个组合,搭任何表单都很快。
两个 demo 对比
| 维度 | 自动关联 | 表单提交 |
|---|---|---|
| 核心组件 | TextField + Popup + ListView |
TextField + Button |
| 联动方式 | onTextChanged 主动触发过滤 |
enabled 属性声明式绑定 |
| 数据流 | 输入 → 过滤 → 显示 → 点击填充 | 输入 → 启用状态 → 点击提交 |
| 适用场景 | 搜索补全、标签联想 | 登录、注册、设置保存 |
从表格能看出两种联动思路:自动补全靠 onTextChanged 写逻辑主动触发,是命令式 ;登录按钮靠 enabled 属性绑定自动同步,是声明式。实际项目里两种常常混着用------计算复杂、要自己控制流程的用命令式,简单依赖关系的用声明式,代码会干净很多。
运行验证
- Qt Creator 打开
qml_textfield/CMakeLists.txt - 按
Ctrl+R运行 - 在左侧导航切换"自动关联"、"表单提交"
- 自动关联:输入
a看弹出a/ab/abc、输入cd看弹出cdef/cdefg/cdefgh、点击候选项看自动填入 - 表单提交:初始看登录按钮禁用(浅蓝)、只填用户名看按钮仍禁用、两个都填看按钮启用(蓝色)、点登录看控制台输出
扩展复用方向
- 把自动补全封装成
AutoCompleteTextField组件,model属性接收数据源,onSelected信号通知选中项 - 自动补全数据源改成动态:
onTextChanged里调 C++ 后端或网络接口,实现搜索引擎式实时建议 - 表单加校验:用户名用正则、密码要求长度 8+ 含大小写,校验未通过时按钮禁用并提示原因
- 登录按钮加
BusyIndicator,点击后显示加载状态,模拟异步请求 - 表单加"记住密码"、"自动登录"勾选框,用
Switch或CheckBox组件配合TextField使用
已验证环境:
- Qt 版本:Qt 6.11.1
- 操作系统:Windows 11
- GitHub:QML-Minimal-Demos/qml_textfield