【Qt】输入类控件1——QLineEdit,QTextEdit,ComboBox
目录
一.QLineEdit
1.1.核心属性
1.2.核心信号
1.3.代码示例1——录入个人信息
1.3.1.输入框一
1.3.2.输入框二
1.3.3.输入框三
1.3.4.完成剩余部分
1.4.代码示例2——使用数据框验证输入框的内容
1.4.1.正则表达式简介
1.4.2.Qt内置验证器对象
1.4.3.示例
1.5.示例3——验证两次输⼊的密码⼀致
1.6.示例4——切换显示/隐藏密码
二.QTextEdit
2.1.核心属性
2.2.核心信号
2.2.1.信号介绍
2.2.2.示例——验证各种信号
2.3.示例1——获取多⾏输⼊框的内容
三. ComboBox
3.1.核心属性
3.2.核心方法
3.3.核心信号
3.4.示例1——使用下拉框模拟麦当劳点餐
3.5.示例2——从文件中加载下拉框的选项
一.QLineEdit
1.1.核心属性
QLineEdit
是一个用于输入和编辑单行文本的控件。它非常灵活,可以通过设置丰富的属性来满足不同的输入需求。
1. text(文本)
-
说明:这是 QLineEdit 最核心的属性,它代表了输入框中当前显示和存储的文本内容。
-
详细解释:
-
你可以通过这个属性来获取用户输入了什么,或者设置输入框中要显示什么初始文本。
-
它是一个字符串(QString)类型。例如,当用户输入“Hello World”时,
text
属性的值就是 "Hello World"。 -
在代码中,通常使用
text()
方法来获取,使用setText("字符串")
方法来设置。 -
这个 text 属性不仅仅可以通过代码来设置,用户在输入框中进行编辑, 也会影响到 text 值的变化~~
-
(1)通过代码中设置 text,界面上的文本会发生改变
-
(2)直接操作修改界面上的文本 (输入框,可以编辑的),text 属性的值也会发生改变
-
2. maxLength(最大长度)
-
说明:限制输入框所能接受的最大字符数。
-
详细解释:
-
设置一个整数,比如
10
,那么用户最多只能输入10个字符。 -
当用户输入的字符数达到最大值后,再按键盘将不会产生任何效果(不会发出
textEdited
等信号),也无法通过粘贴输入更多字符。
-
-
用途:防止用户输入过长的内容,例如限制用户名不能超过20个字符,验证码为6位等。
3. frame(边框)
-
说明:一个布尔值,控制是否显示输入框的默认边框。
-
详细解释:
-
当设置为
True
(默认值)时,QLineEdit 会显示一个具有立体感的矩形边框。 -
当设置为
False
时,边框会消失,QLineEdit 会看起来像一段纯文本,与背景融为一体。通常需要配合设置背景色或调整布局来达到更好的视觉效果。
-
-
用途:用于实现扁平化、简约的UI设计风格。
3. cursorPosition(光标位置)
-
说明:表示文本中闪烁的光标当前所在的位置(索引)。
-
详细解释:
-
位置是从 0 开始计数的。例如,文本 "ABC" 中,光标在 'A' 之前是位置 0,在 'A' 和 'B' 之间是位置 1,在末尾是位置 3。
-
你可以通过程序获取当前光标的位置,也可以设置光标的位置(例如,调用
setCursorPosition(0)
将光标移到开头)。
-
-
用途:在需要精确控制文本插入点或进行文本选择的程序中非常有用。
4. alignment(对齐方式)
-
说明:设置输入框内文本的对齐方式。
-
详细解释:
-
可以使用 Qt 的对齐标志,如:
-
Qt.AlignLeft
:左对齐(默认) -
Qt.AlignRight
:右对齐(常用于数字输入) -
Qt.AlignHCenter
:水平居中 -
Qt.AlignTop
/Qt.AlignBottom
/Qt.AlignVCenter
:垂直方向的对齐(在单行输入框中效果不明显,因为只有一行高度)。
-
-
这些标志可以用
|
运算符组合,例如Qt.AlignRight | Qt.AlignVCenter
表示右下角对齐。
-
-
用途:使界面布局更美观、符合阅读习惯,如金额数字通常右对齐。
5. dragEnabled(允许拖拽)
-
说明:一个布尔值,控制是否允许用户从 QLineEdit 中拖拽选中的文本。
-
详细解释:
-
当设置为
True
时,用户可以在输入框中选中一段文本,然后按住鼠标左键将其拖拽到其他支持拖放(Drop)的应用程序(如文本编辑器)或控件中。 -
当设置为
False
(默认值)时,禁止这种拖拽行为。
-
-
用途:当希望输入框内容可以被轻松复制到别处时,可以开启此功能。
6. readOnly(只读)
-
说明:控制输入框是否为只读状态。
-
详细解释:
-
当设置为
True
时,用户不能通过键盘或鼠标编辑框内的文本。文本看起来通常是灰色的(取决于样式),光标也不会出现。 -
但是,用户通常仍然可以选中文本并复制(Ctrl+C)。
-
这与
setEnabled(False)
(禁用)不同,禁用状态下的控件完全不能交互,且外观更灰。
-
-
用途:用于显示不希望用户修改但又需要让其复制的内容,如计算结果、唯一ID等。
至于更多属性,我们会在下面的例子中进行讲解
1.2.核心信号
cursorPositionChanged(int old, int new)
-
说明:当光标在文本中的位置发生改变时,发出此信号。
-
详细解释:
-
触发时机:无论是通过鼠标点击、键盘方向键移动,还是通过代码设置光标位置,只要光标位置变了就会触发。
-
参数含义:
-
old
:光标之前所在的位置(索引值)。 -
new
:光标现在所在的位置(索引值)。
-
-
位置索引从 0 开始计数,0 表示文本的最开头。
-
-
典型用途:
-
实时显示光标位置(比如在文本编辑器状态栏)。
-
根据光标位置动态改变界面(如显示/隐藏特定的格式工具栏)。
-
editingFinished()
-
说明:当用户"完成编辑"这一动作时发出。
-
详细解释:
-
触发时机:这是一个"复合"触发信号,在以下任一情况发生时都会触发:
-
用户按下 返回键 或 Enter 键。
-
行编辑框失去焦点(例如用户点击了界面上其他控件)。
-
-
它表示用户可能已经输入完毕,准备进行下一步操作。
-
-
典型用途:
-
表单提交:在输入完一个字段后,自动验证或保存数据,而不必等用户点击"提交"按钮。
-
实时搜索:当用户在搜索框中输入完毕(比如移开光标或按回车)后,立即开始搜索。相比于
textChanged
,它可以减少不必要的实时搜索请求。
-
returnPressed()
-
说明:当用户按下 返回键 或 Enter 键时发出。
-
详细解释:
-
触发时机:非常明确,只在用户按下 返回键 或 Enter 键时触发。
-
与验证器的关系:这是一个非常重要的细节。如果为 QLineEdit 设置了验证器(Validator)(用于限制输入格式,比如只允许数字),那么只有当输入的内容通过了验证器的检查时,按下回车才会触发此信号。如果输入内容非法,按下回车不会有任何反应(不会触发信号)。
-
-
典型用途:
-
登录界面:在密码框按回车即可登录,提升用户体验。
-
命令行界面:模拟终端,输入命令后按回车执行。
-
对话框:按回车快速确认并关闭对话框。
-
selectionChanged()
-
说明:当用户选中的文本区域发生改变时发出。
-
selectionChanged()
信号在文本的"选中状态"发生变化时发出。这里的"变化"指的是选中区域的范围、位置或存在性的改变。 -
详细解释:
-
触发时机:只要文本的选中状态变化就触发。包括:
-
从无到有:开始用鼠标拖拽选择文本。
-
从有到无:点击其他地方取消选择。
-
改变范围:用键盘(Shift+方向键)或鼠标调整已选中的区域。
-
-
它不关心选中的具体内容是什么,只关心"选中"这个动作本身发生了变化。
-
-
典型用途:
-
富文本工具栏:当有文本被选中时,显示"加粗"、"斜体"、"复制"等按钮;没有选中时则禁用这些按钮。
-
自定义右键菜单:根据是否有选中文本来决定右键菜单中是否提供"复制"、"剪切"等选项。
-
就像下面两种情况的转换,就会触发这个selectionChanged()信号
textChanged(const QString &text)
-
说明:当输入框中的文本内容发生任何改变时发出。
-
详细解释:
-
触发时机:这是最"敏感"的信号。无论是用户输入(键盘打字、粘贴)还是代码修改(例如调用
setText()
方法),只要text
属性的值变了,它就立即触发。 -
参数:
text
是改变后的最新文本内容。 -
它的触发非常频繁,比如用户输入"abc",它会连续触发三次('a', 'ab', 'abc')。
-
textEdited(const QString &text)
-
说明:当输入框中的文本内容因用户编辑而改变时发出。
-
详细解释:
-
触发时机:这是
textChanged
信号的"子集"。它只在由用户交互导致文本改变时触发。 -
关键区别:如果文本的改变是通过代码(如
setText()
)完成的,这个信号不会被触发。 -
参数:
text
同样是改变后的最新文本内容。
-
-
典型用途:
-
当你需要响应用户的输入行为,但又想避免由程序自动设置文本所引发的副作用时,使用这个信号。
-
1.3.代码示例1——录入个人信息
1)在界面上创建三个输入框和两个单选按钮,一个普通按钮
三个输入框的 objectName为lineEdit_name,lineEdit_password,lineEdit_phone
两个单选按钮的 objectName 为radioButton male,radioButton_female按钮的 objectName 为pushButton
我们先放置3个输入框
再放置两个单选按钮
再来4个Label
我们最后来一个PushButton
这些组件的objectname是
1.3.1.输入框一
现在我们就来编写一下代码
这里事关两个属性
属性一:placeHolderText(占位文本)
-
说明:当输入框的
text
为空时,显示一段灰色的、半透明的提示性文字。 -
详细解释:
-
这串文本只是提示,并非输入框的实际值。一旦用户开始输入(或通过代码设置了
text
),占位文本就会立即消失。 -
如果用户清空了输入框,占位文本会重新出现。
-
例如,在一个搜索框里设置占位文本为“请输入关键词...”,能很好地引导用户操作。
-
-
用途:提供输入提示,引导用户输入正确格式的内容,提升用户体验。
属性二:clearButtonEnabled(清除按钮启用)
-
说明:一个布尔值,控制是否在输入框的右侧自动显示一个清除按钮(通常是一个小叉号)。
-
详细解释:
-
当设置为
True
且输入框不为空时,右侧会出现一个清除按钮。 -
用户点击这个按钮,可以一键清空输入框内的所有文本,非常方便。
-
当输入框为空时,按钮会自动隐藏。
-
-
用途:为用户提供快速清空输入内容的方法,在搜索框、筛选框等需要频繁清空的场景中特别有用。
我们运行一下
可以看到我们什么都不输入的情况下,这个姓名输入框里面就有我们设置的提示词,如果我们往里面输入这个内容的话,大家可以看到这个提示字词没有了。
大家仔细观察的话就会发现输入内容之后,这个输入框右边就有一个叉,我们点击这个叉,就可以快速清除到我们输入框里面的内容,下图就是我们点击了叉的结果
怎么样?很好吧!!!
1.3.2.输入框二
前两个我就不说了,我们直接看第3句
这里事关另外一个属性
echoMode(显示模式)
-
说明:控制输入文本的显示方式,特别是用于密码等敏感信息的输入。
-
详细解释:
-
Normal(正常模式):默认模式。你输入什么,就显示什么。
-
Password(密码模式):输入的字符会被隐藏,通常显示为圆点(•)或星号(*)。具体显示什么字符取决于系统的主题或可以自定义。这是最常用的密码输入方式。
-
NoEcho(无回显模式):输入时,屏幕上完全不显示任何字符。这通常用于安全性要求极高的场合,比如输入超级管理员密码,防止旁人通过观察屏幕上的圆点数量来猜测密码长度。用户体验较差,需谨慎使用。
-
PasswordEchoOnEdit(编辑时回显密码):这是一个折中方案。在编辑时(即获得焦点正在输入时)短暂地以明文显示字符,当失去焦点后,又恢复成密码模式(圆点)。这方便用户确认自己输入的密码是否正确。
-
-
用途:根据输入内容的敏感程度选择合适的模式。
我们运行一下
我们往密码里面输入一些信息
我们发现它居然是使用一个大黑点表示的。这就是Password模式
我们也可以看看其他模式是什么情况
先看看这个NoEcho(无回显模式)
我们运行一下
我们往密码里面输入一些信息
我们发现这里居然不显示,但是我们的内容确实是写进去了
接下来来看看PasswordEchoOnEdit(编辑时回显密码)
我们运行一下
我们往密码里面输入一些信息
过了一会,自动变成下面这样子了
1.3.3.输入框三
这里引入了一个新属性
inputMask(输入掩码)
-
说明:用来强制约束用户输入的格式,确保输入符合特定的模式。
-
详细解释:
-
它使用一些特殊的字符作为占位符来定义格式。例如,
A
代表必须输入一个字母,9
代表必须输入一个数字,#
代表可输入数字或加减号。 -
示例:
-
设置掩码为
000.000.000.000;_
可以强制用户输入一个IP地址(0
代表必须输入数字,_
代表空白时的显示字符)。 -
设置掩码为
>AAAAA-AAAAA-AAAAA-AAAAA-AAAAA;
可以强制输入一个序列号(A
代表字母,>
代表其后的字母自动转为大写)。
-
-
当用户输入时,光标会自动跳到下一个需要输入的位置,不符合格式的字符无法输入。
-
-
用途:用于需要严格格式化的输入,如电话号码、日期、产品序列号、MAC地址等。
常用掩码字符说明
输入掩码由一系列特殊字符组成,这些字符定义了输入字段的格式。以下是一些常用的掩码字符:
-
9
:允许输入数字(0-9)和空格(可选) -
0
:允许输入数字(0-9) -
A
:允许输入字母(A-Z, a-z)和空格(可选) -
a
:允许输入字母(A-Z, a-z) -
N
:允许输入字母和数字(A-Z, a-z, 0-9)和空格(可选) -
X
:允许输入任何字符 -
H
:允许输入十六进制字符(A-F, a-f, 0-9) -
>
:将后续的字母转换为大写 -
<
:将后续的字母转换为小写 -
#
:允许输入数字、加减号和空格(可选) -
\\
:用于转义特殊字符,例如\\-
表示字面意义的-
-
;
:用于分隔掩码字符串和空白字符的处理方式(后面详细说明)
掩码字符串后面可以跟一个分号和一个字符,这个字符表示在输入框中未输入字符时显示的占位符。如果不指定,默认是空格。
我们可以看几个例子
示例1:电话号码格式
// 3位-4位-4位格式的电话号码
ui->lineEdit_phone->setInputMask("000-0000-0000");
// 用户输入: 13912345678 → 显示: 139-1234-5678
// 0 表示必须输入数字
示例2:日期格式
// 年月日格式
ui->lineEdit_date->setInputMask("0000-00-00");
// 用户输入: 20231225 → 显示: 2023-12-25// 带中文分隔符的日期
ui->lineEdit_date_cn->setInputMask("0000年00月00日");
// 用户输入: 20231225 → 显示: 2023年12月25日
示例3:身份证号码格式
// 18位身份证号码,最后一位可以是数字或X
ui->lineEdit_id->setInputMask("000000-00000000-000A");
// 用户输入: 110101199001011234 → 显示: 110101-19900101-1234
// A 表示必须输入字母(A-Z, a-z)
示例4:IP地址格式
// IP地址格式
ui->lineEdit_ip->setInputMask("000.000.000.000");
// 用户输入: 192168001 → 显示: 192.168.0.1
示例5:信用卡号格式
// 信用卡号,4位一组
ui->lineEdit_credit->setInputMask("0000-0000-0000-0000");
// 用户输入: 1234567812345678 → 显示: 1234-5678-1234-5678
示例6:带可选部分的掩码
// 分机号码(总机号码必须,分机可选)
ui->lineEdit_tel->setInputMask("0000-0000; ");
// 用户输入: 12345678 → 显示: 1234-5678
// 用户输入: 12345678 → 显示: 1234-5678
// 分号后的空格表示可选部分的占位符
例子7:时间输入掩码(24小时制)
// 24小时制时间格式,显示下划线占位符
ui->lineEdit_time_24->setInputMask("00:00:00;_");
// 用户看到: __:__:__
// 输入: 142530 → 显示: 14:25:30
事实上,我们知道这些就行了,我们后面都是使用正则表达式的。
现在我们应该懂了很多吧,我们运行看看
我们看到这个电话这里已经出现了两条-。
我们输入一下
输入完这些数字之后,我们再输入的文字就失效了。
1.3.4.完成剩余部分
现在我只是完成了的输入框的设计,我们还需要完成整个项目,我们按下确认按钮,得有反应吧。
我们运行一下
点击确认
怎么样?还行吧!!!
inputMask只能进⾏简单的输⼊格式校验.
实际开发中,基于正则表达式的⽅式是更核⼼的⽅法.
1.4.代码示例2——使用数据框验证输入框的内容
1.4.1.正则表达式简介
⚽ 关于正则表达式 正则表达式是⼀种在计算机中常⽤的,
使⽤特殊字符描述⼀个字符串的特征的机制
在进⾏字符串匹配时⾮常有⽤.
正则表达式的语法还⽐较复杂,⼀般都是随⽤随查,不需要背下来.
- 正则表达式文档:正则表达式语法 | Microsoft Learn
- 正则表达式在线工具:正则表达式语法测试工具 - 在线工具
我在这里给大家讲一个正则表达式
^1\\d{10}$
我们来把 ^1\\d{10}$ 这个表达式拆开看,每一部分都代表一个规则:
- ^ (脱字符)
它表示一个字符串的开始。
规则:匹配的字符串必须从这个位置开始。
- 1
这是一个普通的字符,就是数字“1”。
规则:字符串的第一个字符必须是数字 1。这正是中国大陆手机号的开头数字(如139、188、199等号段)。
- \\d (注意是双反斜杠)
\d 是正则表达式中的一个特殊字符,代表任意一个数字(0-9)。在代码字符串中,由于反斜杠 \ 本身是转义字符,所以要表示一个真正的 \,需要写成 \\。因此,\\d 在正则引擎看来就是 \d。
规则:匹配一个数字。
- {10} (量词)
它紧跟在 \\d 后面,表示前面的元素(也就是 \\d)必须连续出现10次。
规则:在开头的 1 之后,必须紧跟着10个数字。
- $ (美元符号)
它表示一个字符串的结束。
规则:匹配的字符串必须在这个位置结束。
总结一下规则
把所有这些规则组合起来,这个正则表达式的完整要求是:
从字符串开头(^)到结尾($),必须完全符合“一个数字1(1)后面紧跟着恰好10个数字(\\d{10})”这个模式。
简单来说,它的意思是:匹配一个以数字1开头,后面跟着10位数字的字符串。
举例说明
哪些字符串能匹配?
- 13812345678 ✅ (11位,以1开头)
- 19987654321 ✅ (11位,以1开头)
哪些字符串不能匹配?
- 1381234567 ❌ (只有10位数字,少了1位)
- 23812345678 ❌ (12位,但开头不是1)
- 138-1234-5678 ❌ (包含了非数字字符 -)
- 我的手机是13812345678 ❌ (开头有其它字符,违反了 ^ 规则)
- 13812345678abc ❌ (结尾有其它字符,违反了 $ 规则)
在Qt中怎么使用正则表达式?
Qt 提供了两个主要的类来处理正则表达式,它们代表了两个不同的时代:
-
QRegExp:这是 Qt 早期版本(Qt 1.x 到 Qt 4.x)中使用的传统正则表达式引擎。
-
QRegularExpression:这是从 Qt 5.0 开始引入的现代正则表达式引擎。目前(Qt 5 和 Qt 6 时代),QRegularExpression 是官方推荐使用的类。
在接下来的例子中,我将使用QRegularExpression来演示
1.4.2.Qt内置验证器对象
Qt中内置了四个主要的验证器对象。
它们都是QValidator的子类
那么我们就先讲讲这个QValidator
一、QValidator 是什么?—— 给它一个形象的角色
你可以把 QValidator 想象成一位严格而又聪明的「输入质检员」。
它的工作岗位,就是守在文本框、输入框这类需要用户输入内容的地方。每当用户通过键盘输入一个字符,这位「质检员」就会立刻介入,判断这个新输入的字符,或者当前整个输入的内容,是否符合你(程序员)预先设定好的「质量标准」。
它的核心任务不是等用户全部输完了再报错,而是在输入的过程中就进行实时监督和引导,确保最终得到的数据是干净、合规的。
二、QValidator 的核心工作原则:三种判定状态
这位「质检员」在工作中,对任何输入内容只会做出以下三种判定。理解这三种状态是理解 QValidator 的关键:
-
「合格」(QValidator::Acceptable)
-
含义:当前输入框中的内容完全符合所有规则,是完美无缺的。
-
比喻:就像你填写一份表格,所有必填项都填了,格式也完全正确(比如身份证号正好是18位)。质检员会亮起绿灯。
-
在程序中的表现:输入框通常显示为正常的样式(比如白色背景),程序可以安全地读取并使用这个数据。
-
-
「待定」(QValidator::Intermediate)
-
含义:当前的内容还不完整或不完全符合规则,但它有「潜力」通过继续输入变成「合格」的。这是一个非常有用且人性化的状态。
-
比喻:最典型的例子是输入手机号。规则是11位数字。当你只输入了前3位(如“139”)时,它虽然不完整,但方向是正确的,没有错误。质检员会亮起黄灯,意思是“请继续,但还没完成”。
-
在程序中的表现:输入框可能会显示一个温和的提示(比如淡黄色背景),告诉用户需要继续输入。程序不应该使用这个状态下的数据。
-
-
「不合格」(QValidator::Invalid)
-
含义:当前输入的内容(尤其是刚输入的字符)根本违反了核心规则,并且无论如何继续输入,它都不可能变成「合格」。
-
比喻:同样在只能输入数字的框里,你试图输入一个字母“A”。这个“A”本身就是非法的。质检员会立刻亮起红灯,并常常会拒绝这个字符进入输入框。
-
在程序中的表现:输入框可能会变成醒目的警告色(如红色),或者最常见的是,那个非法的字符根本就输不进去,你按键后会发现输入框没有任何变化。
-
简单总结三态关系:
-
合格:完美,可用。
-
待定:不完美,但允许你继续朝着完美的方向努力。
-
不合格:错误,且不允许存在。
我们可以去代码里面看看是什么样子的:
三、常用的几种「质检员」(内置验证器类型)
Qt 为我们提供了几种现成的、具有不同专业技能的「质检员」:
-
整数质检员(QIntValidator)
-
专业技能:只允许输入整数,并且可以规定这个整数的范围(例如,从 0 到 150)。
-
工作场景:适合用来检查「年龄」、「数量」等。
-
如何工作:你告诉他:“只允许检查 0 到 150 之间的整数。” 然后他上岗。用户输入“50”,他判「合格」;输入“2”,他判「待定」(因为可能想输入“25”);输入“abc”或“200”,他判「不合格」。
-
-
浮点数字检员(QDoubleValidator)
-
专业技能:允许输入小数。可以规定数值范围和小数点后的位数。
-
工作场景:适合用来检查「身高」、「体重」、「价格」等。
-
如何工作:你告诉他:“只允许检查 0.5 到 2.5 之间,且最多一位小数。” 用户输入“1.7”,判「合格」;输入“1.”(只输入了小数点),判「待定」(用户可能正要输入小数部分);输入“3.0”或“1.2a”,判「不合格」。
-
-
万能正则表达式质检员(QRegularExpressionValidator)
-
专业技能:最强大、最灵活的质检员。它使用一种叫做「正则表达式」的强大规则描述语言,可以定义极其复杂的规则。
-
工作场景:检查「电子邮箱」、「手机号」、「身份证号」、「邮政编码」等有固定复杂格式的数据。
-
如何工作:你用一种特定的文本模式(正则表达式)告诉他规则。比如,手机号的规则可能是“以1开头,总长度为11位的数字”。用户输入“13912345678”,判「合格」;输入“139”,判「待定」(长度不够但格式对);输入“239”或“139abc”,判「不合格」。
-
上面这些就是我们说的QValidator的子类
在接下来的例子中,我们就将使用万能正则表达式质检员(QRegularExpressionValidator)。
1.4.3.示例
我们创建一个新的项目
在界⾯上创建输⼊框和⼀个按钮.
我们现在就来编写代码
现在我们来给输入框配置槽函数
我们讲讲这个信号
textEdited(const QString &text)
-
说明:当输入框中的文本内容因用户编辑而改变时发出。
-
详细解释:
-
触发时机:这是
textChanged
信号的"子集"。它只在由用户交互导致文本改变时触发。 -
关键区别:如果文本的改变是通过代码(如
setText()
)完成的,这个信号不会被触发。 -
参数:
text
同样是改变后的最新文本内容。
-
我们写一下代码
我知道大家又懵了
一.lineEdit->validator()
是什么?
想象一下,你给一个输入框(lineEdit
)配备了一位专属的"质检员"(就是我们之前讲的 QValidator
)。
lineEdit->validator()
就像是你在询问这个输入框:"嘿,你的质检员是谁?"
-
作用:这是一个方法(函数),调用它会返回当初你给这个
lineEdit
设置的验证器对象。 -
返回值:它返回的是一个指向
QValidator
类型对象的指针。这个指针就像是你和那位"质检员"之间的"对讲机"或"联系方式"。 -
前提:只有在你之前通过
setValidator
方法给这个lineEdit
指派过质检员,这个调用才会返回一个有效的指针。如果没指派过,它会返回一个空指针(nullptr
),表示"我这里没有质检员"。
简单说:lineEdit->validator()
就是获取绑定在该输入框上的验证器对象的方法。
二. 验证器的
validate()
方法是什么?
现在你拿到了"质检员"的联系方式(指针),接下来就需要让它开始工作。
validate()
方法就是你向质检员下达的指令:"请检查一下这段文字合不合格!"
这个方法就是 QValidator
这个"质检员"最核心的工作职能。
validate
方法的两个参数:
-
第一个参数(QString& input):
-
作用:这是你要交给质检员检查的"文本样品"。也就是你想判断是否合规的那段字符串。
-
QString&
的含义:这里的&
符号表示这是一个"引用"。通俗地讲,质检员收到的不是一份文本的"复印件",而是"原件"本身。这意味着,理论上质检员有权直接修改你交给他的这份文本(比如,自动帮你格式化:删除空格、纠正大小写等)。这就是为什么注释里说,如果你不想让原文本被修改,需要先复制一份再传给它。你把原件给了它,它可能会在上面涂改。 -
这就是我们为啥已经有了arg1,然后还需要创建一个新的临时变量
QString content = arg1;,然后再将content传进去的原因
-
-
第二个参数(int& pos):
-
作用:这是一个"输出型参数"。可以把它想象成质检员给你的一个"问题报告单"上的一个特定栏目。
-
它的值:当文本验证失败(返回
Invalid
状态)时,这个参数通常会被设置为第一个出问题的字符在文本中的位置(索引)。例如,文本是 "12a45",规则是只能输入数字,那么pos
可能会被设置为 2(因为索引从0开始,'a' 是第3个字符,索引为2)。 -
实用性:正如注释所说,在很多简单应用场景下,我们只关心"合格"还是"不合格",并不太关心具体哪个位置出错。所以这个参数常常被忽略,被认为"没有实质作用"。但它对于需要精确定位错误的高级功能是有用的。
-
validate
方法的返回值:
这个方法执行完毕后,质检员会给你一个明确的"检验结果"。这个结果就是之前讲过的三种状态枚举值:
-
QValidator::Acceptable
:质检员说:"这段文本完美,完全符合规则!" -
QValidator::Intermediate
:质检员说:"这段文本目前还不完全符合,但有潜力,继续输入可能就会达标。"(例如,手机号输了前5位) -
QValidator::Invalid
:质检员说:"这段文本有问题!违反了核心规则,不可能通过继续输入变得合格。"(例如,在数字框里输入了字母)
我们运行一下
发现这个确认按钮默认就是禁用的
我们输入一些字母看看
发现它根本就不接受字母,字母根本打不进去。
我们试着输入10位数字
我们发现这个确认按钮还是禁用状态
我们试着输入11位数字
我们发现这个按钮终于被启用了。
只有当输⼊的内容符合要求,确 定按钮才能被使⽤
1.5.示例3——验证两次输⼊的密码⼀致
我们创建一个新项目
1) 在界⾯上创建两个输⼊框和⼀个label
它们的objectname分别是
编写代码,设置两个输⼊框的 echoMode 为 Password,并且给两个输⼊框设置 textEdited slot函数
这里的信号需要讲解一下。
textEdited(const QString &text)
-
说明:当输入框中的文本内容因用户编辑而改变时发出。
-
详细解释:
-
触发时机:这是
textChanged
信号的"子集"。它只在由用户交互导致文本改变时触发。 -
关键区别:如果文本的改变是通过代码(如
setText()
)完成的,这个信号不会被触发。 -
参数:
text
同样是改变后的最新文本内容。
-
-
典型用途:
-
当你需要响应用户的输入行为,但又想避免由程序自动设置文本所引发的副作用时,使用这个信号。
-
我们运行一下程序
我们输入一下
怎么样?还是可以的吧
1.6.示例4——切换显示/隐藏密码
1) 创建⼀个输⼊框和⼀个复选按钮.
它们的objectname分别是
我们现在就来编写一下代码
接着我们给 checkBox 添加slot函数
我们来复习一下这个信号
toggled(bool) - 状态切换
触发时机:当按钮的状态发生改变时触发。这个信号是可切换按钮(如 QPushButton 设置为 setCheckable(true)、QRadioButton、QCheckBox)特有的。
行为特点:
- 它带有一个 bool 参数,表示按钮的新状态(true 表示选中/开,false 表示未选中/关)。
- 它的触发是状态驱动的,而不是直接由一次点击驱动。一次点击可能会引起状态变化,从而触发 toggled。但如果通过代码(例如 setChecked(true))改变状态,同样会触发 toggled 信号。
- 一个可切换按钮被点击时,会同时发射 clicked() 和 toggled(bool) 两个信号。
我们运行一下程序看看
输入123
可以看到默认就是密码模式,现在我们点击显示密码
现在我们关闭显示密码
怎么样?还是可以的吧
二.QTextEdit
QTextEdit 表⽰多⾏输⼊框.也是⼀个富⽂本&markdown编辑器. 并且能在内容超出编辑框范围时⾃动提供滚动条.
2.1.核心属性
这是一个功能非常丰富的文本输入框的属性列表。
我们可以把它们分成几大类来理解:
第一类:内容与格式 (Content & Formatting)
这些属性决定了输入框里能放什么内容,以及内容如何被处理和显示。
-
markdown
-
含义:输入框内存储的原始文本内容,这个内容是使用 Markdown 语法 编写的。
-
详细解释:Markdown 是一种轻量级标记语言,用简单的符号(如
#
表示标题,**粗体**
表示加粗)来定义格式。这个属性值就是用户输入的这些带标记的纯文本。它的强大之处在于,编辑器能够自动将这些 Markdown 文本实时渲染成美观的、格式化的 HTML 内容(见下一个属性html
)供用户阅读。非常适合需要兼顾“方便写作”和“美观显示”的场景,比如写博客、笔记等。
-
-
html
-
含义:由 Markdown 内容自动渲染后生成的,或用户直接输入的 HTML 代码。
-
详细解释:这是最终呈现给用户看的、经过格式化的内容。它支持大部分 HTML 标签,这意味着你可以在里面插入图片 (
<img>
)、创建复杂的表格 (<table>
)、添加链接等,实现非常丰富的排版效果。通常,markdown
和html
这两个属性是关联的:用户编辑markdown
,程序自动更新html
。但在某些模式下,也可能允许用户直接编辑html
代码。
-
-
acceptRichText
-
含义:控制输入框是否接收和显示富文本内容。
-
详细解释:这是一个总开关。如果设置为
false
(关闭),那么输入框将只接受纯文本。即使用户从其他网页或Word文档中复制了带有格式(如字体、颜色、加粗)的内容粘贴进来,这些格式也会被自动剥离,只留下纯文字。如果设置为true
(开启),则粘贴或输入的内容可以保留其原有的富文本格式。这个功能可以防止格式混乱。
-
-
autoFormating
-
含义:是否开启自动格式化。
-
详细解释:这是一个提升写作体验的功能。开启后,编辑器会在你输入时自动帮你完成一些格式调整。例如,自动将直引号
" "
转换为更美观的弯引号“ ”
,或者自动将网络地址和邮箱地址转换为可点击的链接。它让你专注于内容,而不用操心一些琐碎的格式细节。
-
第二类:行为与交互 (Behavior & Interaction)
这些属性控制了用户如何与输入框进行交互。
-
readOnly
-
含义:输入框是否为只读模式。
-
详细解释:如果设置为
true
(是),那么用户将无法对输入框内的内容进行任何修改、删除或添加。它看起来和正常输入框一样,但光标无法聚焦或无法输入。这个模式常用于显示文档、说明、代码等,让用户只能阅读而不能编辑。
-
-
undoRedoEnable
-
含义:是否开启撤销 (Undo) 和重做 (Redo) 功能。
-
详细解释:这是文本编辑中至关重要的功能。开启后,系统会记录你的每一步操作。
-
撤销 (Undo):当你误操作(如误删一大段文字)时,可以按下
Ctrl + Z
来撤销上一步操作,恢复到之前的状态。 -
重做 (Redo):如果你撤销了某一步但又反悔了,可以按下
Ctrl + Y
,将刚刚撤销的操作重新执行。
这相当于为你的编辑工作提供了“后悔药”。
-
-
-
overwriteMode
-
含义:是否开启覆盖写模式(也叫“改写模式”)。
-
详细解释:我们通常的输入模式是“插入模式”,即你在两个字中间输入新字,原来的字会向后移动。而“覆盖模式”下,你在两个字中间输入新字,新字会直接覆盖掉光标后面的那个字。这个功能在某些特定的表格数据录入场景下有用,但日常写作中较少使用。
-
-
tabstopWidth
-
含义:按下
Tab
键时,缩进所占的空格宽度。 -
详细解释:在编写代码或需要层级结构的文本时,我们常用
Tab
键来缩进。这个属性就是用来定义一次Tab
缩进相当于多少个空格的宽度。例如,通常编程时会设置为4
,表示按一次Tab
键,就插入相当于 4 个空格的缩进量。
-
第三类:视觉与提示 (Visual & Hint)
这些属性关乎输入框的外观和给用户的提示。
-
placeHolderText
-
含义:输入框为空时显示的提示文本。
-
详细解释:这个灰色、半透明的提示文字用于引导用户应该在这里输入什么内容。一旦用户开始输入,提示文字就会自动消失。非常常见的例子就是搜索框里的“请输入关键词...”。
-
第四类:滚动条控制 (Scrollbar Control)
这些属性决定了滚动条何时出现。
verticalScrollBarPolicy 和 11. horizontalScrollBarPolicy
-
含义:分别控制垂直滚动条和水平滚动条的显示策略。
-
详细解释:它们都有三个相同的选项:
-
Qt::ScrollBarAsNeeded(按需显示):这是最智能、最常用的默认选项。只有当输入框里的内容多到一屏显示不下时,相应的滚动条才会自动出现。内容不多时,滚动条会隐藏,以节省空间。
-
Qt::ScrollBarAlwaysOff(总是关闭):无论内容有多少,都永不显示滚动条。即使用户无法通过滚动看到超出范围的内容,滚动条也不会出现。适用于那些内容高度固定或需要通过其他方式(如缩放)来查看全部内容的场景。
-
Qt::ScrollBarAlwaysOn(总是开启):无论内容是否超出范围,始终显示滚动条。这样做的目的是保持界面布局的稳定,避免因为滚动条突然出现或消失而导致的内容区域宽度变化。
-
2.2.核心信号
2.2.1.信号介绍
1. textChanged()
-
信号含义:文本内容发生任何改变时,立即触发。
-
详细解释:这是最常用、最核心的信号。无论用户是通过键盘输入、粘贴、删除,还是通过程序代码修改了编辑器里的文本内容,只要文本变了,这个信号就会被发射出去。
-
典型应用场景:
-
实时预览:在 Markdown 编辑器中,一边打字,一边在另一个区域实时渲染预览。只需将
textChanged()
信号连接到负责渲染的函数即可。 -
自动保存:用户每输入一个字符,都可以触发一个自动保存的倒计时。
-
语法高亮:代码编辑器需要根据内容变化实时更新语法高亮。
-
修改标识(“脏”标志):在类似 Word 的软件中,如果文档被修改了但未保存,标题栏会显示一个
*
号。这个功能就可以通过监听textChanged()
信号来实现。
-
2. selectionChanged()
这个和文本选中有关,什么叫文本选中?
上面两个就是不同的文本选中。
-
信号含义:用户用鼠标或键盘改变文本选中范围时触发。
-
详细解释:当用户拖拽鼠标选中一段文字,或用
Shift + 方向键
改变选中范围时,这个信号就会发出。如果用户只是移动光标而没有选中文字,或者取消了选中(例如用鼠标点击别处),这个信号同样会触发,因为它表示“选中状态”发生了变化。 -
典型应用场景:
-
更新工具栏按钮状态:只有当用户选中了文字后,“剪切”、“复制”、“设置粗体”、“设置颜色”等按钮才应该变为可用状态。这个信号就是用来通知程序“选中状态已改变,请更新相应按钮”的完美时机。
-
3. cursorPositionChanged()
-
信号含义:光标的位置发生移动时触发。
-
详细解释:只要闪烁的光标移动了(无论是通过鼠标点击、键盘方向键移动,还是因为输入/删除文本导致光标自然移动),这个信号就会被发射。
-
典型应用场景:
-
更新状态栏信息:很多文本编辑器(如 Notepad++、VS Code)的状态栏会实时显示当前光标所在的行号和列号。这个功能就是通过监听
cursorPositionChanged()
信号,然后在槽函数中计算并更新状态栏文字来实现的。
-
4. undoAvailable(bool available) 和 redoAvailable(bool available)
想要搞清楚这两个信号,必须得先搞清楚下面这些
撤销(Undo)的含义
撤销,通常对应快捷键 Ctrl+Z,它的意思是:取消最近一次的操作,将文档恢复到该操作之前的状态。
举个例子:
-
你打开一个空文档,输入了字母"A",现在文档内容是"A"。
-
你觉得自己输错了,按下Ctrl+Z,那么这次输入操作被撤销,文档内容又变回空。
撤销功能可以连续进行,也就是说,你可以一步一步地撤销之前的多个操作,直到恢复到文档的初始状态(或者直到撤销栈为空)。
重做(Redo)的含义
重做,通常对应快捷键 Ctrl+Y 或 Ctrl+Shift+Z,它的意思是:重新执行最近一次被撤销的操作,将文档恢复到撤销操作之前的状态。
继续上面的例子:
-
你输入"A"后,按Ctrl+Z撤销了,文档变空。
-
但你突然又觉得那个"A"是对的,于是按下Ctrl+Y,那么被撤销的输入操作被重新执行,文档内容又变回"A"。
重做功能只能在撤销之后使用,而且只能按撤销的顺序反向重新执行操作。如果你在撤销之后又进行了新的操作,那么重做栈会被清空,也就是说你不能重做在新操作之前被撤销的那些操作了。
工作原理简述
编辑器内部会维护两个栈(或历史记录列表):
-
撤销栈(Undo Stack):保存用户执行过的操作(如输入、删除等),每个操作都包含足够的信息来撤销它。
-
重做栈(Redo Stack):保存被撤销的操作,以便可以重做。
当用户执行一个操作时:
-
这个操作会被记录到撤销栈中,同时重做栈会被清空(因为新的操作改变了文档状态,重做栈中的操作已经不再适用)。
当用户执行撤销时:
-
从撤销栈中弹出最近的操作,并执行该操作的逆向操作(即撤销它),然后把这个操作放入重做栈。
当用户执行重做时:
-
从重做栈中弹出最近被撤销的操作,并执行它(即重做),然后把这个操作放回撤销栈。
重要特性
-
线性操作:撤销和重做是严格按顺序的,你不能跳过中间步骤去撤销一个更早的操作。
-
分支清除:一旦在撤销后执行了新的操作,重做栈就会被清空。这意味着你不能再重做那些被清除的操作。这就像你走到一个岔路口选择了一条新路,就不能再走另一条路了。
-
操作粒度:有时一个操作可能包含多个子操作(比如自动更正可能会替换多个字符),但编辑器通常会将它们作为一个整体来撤销/重做。
实际应用中的例子
假设我们有一个文档,初始为空。
-
输入"hello" -> 文档变为"hello",撤销栈记录了这个输入操作。
-
输入" world" -> 文档变为"hello world",撤销栈有两个操作。
-
按Ctrl+Z(撤销) -> 撤销第二个操作,文档变回"hello",被撤销的操作被移到重做栈。
-
按Ctrl+Z(撤销) -> 撤销第一个操作,文档变回空,撤销栈空,重做栈有两个操作(按顺序是输入"hello"和输入" world")。
-
按Ctrl+Y(重做) -> 重做栈顶的操作(输入"hello")被重做,文档变为"hello",这个操作被移回撤销栈。
-
按Ctrl+Y(重做) -> 重做下一个操作(输入" world"),文档变为"hello world"。
如果在第5步后,我们没有重做第二步,而是输入了"abc":
-
那么重做栈中"输入 world"的操作会被清空,我们不能再通过重做来得到"hello world"了。
好了,搞明白上面这些东西了,我们现在就可以来讲这些信号了。
4.1. undoAvailable(bool available)
这个信号在“是否可以执行撤销操作”的状态发生变化时触发。具体来说:
-
从不可撤销变为可以撤销(available = true):
当用户执行了一个可以撤销的修改操作(例如:输入一个字符、删除一段文字、粘贴内容等)时,如果之前撤销栈是空的(即之前不能执行撤销),那么现在有了一个操作记录,撤销变为可用,因此会触发undoAvailable(true)。 -
从可以撤销变为不可撤销(available = false):
当用户连续执行撤销操作,直到撤销栈中没有任何操作记录时,就会触发undoAvailable(false)。另外,如果编辑器被清空(例如通过代码设置一个空文本)并且撤销栈被清空,也会触发。 -
注意:如果用户进行多个操作,然后执行撤销,但并没有撤销到最开始(即撤销栈中还有操作),那么撤销仍然可用,不会触发undoAvailable(false)。只有当撤销栈为空时,才会触发false。
-
特殊情况:如果编辑器被设置为只读(readOnly),那么用户不能编辑,所以通常不会触发undoAvailable(true),因为用户不能进行修改。但是,如果通过程序代码修改文本(例如调用setText),则可能会根据编辑器的设置决定是否记录撤销操作。
-
非用户操作:通过代码修改编辑器内容时,如果这个修改被记录到撤销栈(取决于编辑器的实现和设置),也会影响撤销状态的可用性,从而触发信号。
4.2.redoAvailable(bool available)
这个信号在“是否可以执行重做操作”的状态发生变化时触发。具体来说:
-
从不可重做变为可以重做(available = true):
当用户执行了一次或多次撤销操作后,重做栈中有了操作记录,这时重做变为可用,会触发redoAvailable(true)。注意,只要重做栈从空变为非空,就会触发。 -
从可以重做变为不可重做(available = false):
当用户执行了重做操作,直到重做栈为空时,会触发redoAvailable(false)。另外,如果用户在撤销后进行了新的编辑操作(即用户没有执行重做,而是输入了新的内容),那么重做栈会被清空(因为新的编辑操作使重做栈中的操作记录变得无效),这时也会触发redoAvailable(false)。 -
注意:重做栈的清空时机:当用户在执行了撤销操作后,没有进行重做,而是进行了新的编辑操作,那么重做栈会被清空。这是因为新的编辑操作与重做栈中的操作可能产生冲突,而且线性编辑历史中不能有分叉。
-
非用户操作:通过代码执行撤销或重做,或者通过代码修改内容(可能清空重做栈)也会触发相应的信号。
示例场景
假设编辑器初始状态为空,撤销和重做都不可用。
-
用户输入字符'A':
-
撤销栈中记录了这个操作,撤销变为可用:触发undoAvailable(true)。
-
重做栈为空,重做不可用(不变,不触发信号)。
-
-
用户输入字符'B':
-
撤销栈中又记录了一个操作,撤销仍然可用(不变,不触发undoAvailable信号)。
-
重做栈为空,重做不可用(不变)。
-
-
用户按Ctrl+Z(撤销):
-
撤销栈弹出操作'B',编辑器文本变回"A"。
-
撤销栈中还有一个操作(操作'A'),所以撤销仍然可用(不变)。
-
重做栈中压入了操作'B',重做从不可用变为可用:触发redoAvailable(true)。
-
-
用户按Ctrl+Z again(撤销):
-
撤销栈弹出操作'A',编辑器文本变回空。
-
撤销栈为空,撤销从可用变为不可用:触发undoAvailable(false)。
-
重做栈中压入了操作'A',重做栈非空(重做可用,但之前已经可用了,所以不变)。
-
-
用户按Ctrl+Y(重做):
-
重做栈弹出操作'A',编辑器文本变为"A"。
-
撤销栈中压入操作'A',撤销从不可用变为可用:触发undoAvailable(true)。
-
重做栈中还有操作'B'(重做仍然可用,不变)。
-
-
用户按Ctrl+Y again(重做):
-
重做栈弹出操作'B',编辑器文本变为"AB"。
-
撤销栈中压入操作'B',撤销可用(不变)。
-
重做栈为空,重做从可用变为不可用:触发redoAvailable(false)。
-
-
用户输入字符'C':
-
编辑器内容变为"ABC"。
-
撤销栈中记录操作'C',撤销可用(不变)。
-
重做栈被清空(因为新的编辑操作),重做已经不可用(不变,不触发信号)。
-
但是,注意在第7步中,如果重做栈在清空时之前是非空的(即重做可用),那么清空重做栈会触发redoAvailable(false)。在上面的例子中,第6步后重做栈已经为空,所以第7步不会触发redoAvailable(false)。
另一个例子:如果在第4步后(此时撤销不可用,重做可用)用户直接输入字符'C':
- - 编辑器内容变为"C"。
- - 撤销栈中记录操作'C',撤销从不可用变为可用:触发undoAvailable(true)。
- - 重做栈被清空(因为新的编辑操作),重做从可用变为不可用:触发redoAvailable(false)。
5. copyAvailable(bool yes)
-
信号含义:当文本的“可复制”状态改变时触发。 具体来说,就是当有文本被选中时触发
true
,当选中被取消时触发false
。 -
详细解释:这个信号和
selectionChanged()
非常相似,但关注点略有不同。selectionChanged()
更侧重于“选中范围”这个事实本身,而copyAvailable(bool)
更直接地告诉你当前是否存在可以用于复制或剪切的选中文本。 -
典型应用场景:
-
控制“复制”、“剪切”按钮:虽然用
selectionChanged()
也能实现,但copyAvailable(bool)
信号传递的参数bool yes
更加直接。你可以直接将它连接到“复制”和“剪切”按钮的setEnabled
槽函数上。 -
connect(textEdit, &QTextEdit::copyAvailable, copyAction, &QAction::setEnabled);
-
这样一行代码,就可以完美实现选中文本时按钮可用,未选中时按钮禁用的效果。
-
2.2.2.示例——验证各种信号
我们创建一个项目
2) 给输⼊框添加以下⼏个slot函数
编写一下代码
这里需要验证的信号有很多,我们分批次来验证一下。
先来看看下面两个信号
1. textChanged()
-
信号含义:文本内容发生任何改变时,立即触发。
-
详细解释:这是最常用、最核心的信号。无论用户是通过键盘输入、粘贴、删除,还是通过程序代码修改了编辑器里的文本内容,只要文本变了,这个信号就会被发射出去。
2. cursorPositionChanged()
-
信号含义:光标的位置发生移动时触发。
-
详细解释:只要闪烁的光标移动了(无论是通过鼠标点击、键盘方向键移动,还是因为输入/删除文本导致光标自然移动),这个信号就会被发射。
编写内容时, textChanged 和 cursorPositionChanged 会触发
从日志来看,每次输入一个字符后,cursorPositionChanged
信号都触发了两次,而且位置值相同。这个我们不必关心,只需要知道有这么一回事即可。
接下来看看这3个信号
1.cursorPositionChanged()
-
信号含义:光标的位置发生移动时触发。
-
详细解释:只要闪烁的光标移动了(无论是通过鼠标点击、键盘方向键移动,还是因为输入/删除文本导致光标自然移动),这个信号就会被发射。
2. selectionChanged()
这个和文本选中有关,什么叫文本选中?
上面两个就是不同的文本选中。
-
信号含义:用户用鼠标或键盘改变文本选中范围时触发。
-
详细解释:当用户拖拽鼠标选中一段文字,或用
Shift + 方向键
改变选中范围时,这个信号就会发出。如果用户只是移动光标而没有选中文字,或者取消了选中(例如用鼠标点击别处),这个信号同样会触发,因为它表示“选中状态”发生了变化。
3. copyAvailable(bool yes)
-
信号含义:当文本的“可复制”状态改变时触发。 具体来说,就是当有文本被选中时触发
true
,当选中被取消时触发false
。 -
详细解释:这个信号和
selectionChanged()
非常相似,但关注点略有不同。selectionChanged()
更侧重于“选中范围”这个事实本身,而copyAvailable(bool)
更直接地告诉你当前是否存在可以用于复制或剪切的选中文本。
选中⼀段⽂本时, cursorPositionChanged , selectionChanged , copyAvailable会触发.
注意我是从1的前面一直往后选中文字,直到3的位置
这个时候,如果我们取消选择文字的话(注意我这里是在3的后面点击了一下来取消选择文字的。鼠标位置没有变,所以才不会触发cursorPositionChanged信号)
我们发现还是会触发这个selectionChanged , copyAvailable信号。
接下来我们来讲讲这些信号
1. textChanged()
-
信号含义:文本内容发生任何改变时,立即触发。
-
详细解释:这是最常用、最核心的信号。无论用户是通过键盘输入、粘贴、删除,还是通过程序代码修改了编辑器里的文本内容,只要文本变了,这个信号就会被发射出去。
2. undoAvailable(bool available)
这个信号在“是否可以执行撤销操作”的状态发生变化时触发。具体来说:
-
从不可撤销变为可以撤销(available = true):
当用户执行了一个可以撤销的修改操作(例如:输入一个字符、删除一段文字、粘贴内容等)时,如果之前撤销栈是空的(即之前不能执行撤销),那么现在有了一个操作记录,撤销变为可用,因此会触发undoAvailable(true)。 -
从可以撤销变为不可撤销(available = false):
当用户连续执行撤销操作,直到撤销栈中没有任何操作记录时,就会触发undoAvailable(false)。另外,如果编辑器被清空(例如通过代码设置一个空文本)并且撤销栈被清空,也会触发。 -
注意:如果用户进行多个操作,然后执行撤销,但并没有撤销到最开始(即撤销栈中还有操作),那么撤销仍然可用,不会触发undoAvailable(false)。只有当撤销栈为空时,才会触发false。
-
特殊情况:如果编辑器被设置为只读(readOnly),那么用户不能编辑,所以通常不会触发undoAvailable(true),因为用户不能进行修改。但是,如果通过程序代码修改文本(例如调用setText),则可能会根据编辑器的设置决定是否记录撤销操作。
-
非用户操作:通过代码修改编辑器内容时,如果这个修改被记录到撤销栈(取决于编辑器的实现和设置),也会影响撤销状态的可用性,从而触发信号。
3.redoAvailable(bool available)
这个信号在“是否可以执行重做操作”的状态发生变化时触发。具体来说:
-
从不可重做变为可以重做(available = true):
当用户执行了一次或多次撤销操作后,重做栈中有了操作记录,这时重做变为可用,会触发redoAvailable(true)。注意,只要重做栈从空变为非空,就会触发。 -
从可以重做变为不可重做(available = false):
当用户执行了重做操作,直到重做栈为空时,会触发redoAvailable(false)。另外,如果用户在撤销后进行了新的编辑操作(即用户没有执行重做,而是输入了新的内容),那么重做栈会被清空(因为新的编辑操作使重做栈中的操作记录变得无效),这时也会触发redoAvailable(false)。 -
注意:重做栈的清空时机:当用户在执行了撤销操作后,没有进行重做,而是进行了新的编辑操作,那么重做栈会被清空。这是因为新的编辑操作与重做栈中的操作可能产生冲突,而且线性编辑历史中不能有分叉。
-
非用户操作:通过代码执行撤销或重做,或者通过代码修改内容(可能清空重做栈)也会触发相应的信号。
4.cursorPositionChanged()
-
信号含义:光标的位置发生移动时触发。
-
详细解释:只要闪烁的光标移动了(无论是通过鼠标点击、键盘方向键移动,还是因为输入/删除文本导致光标自然移动),这个信号就会被发射。
好了,我们现在来实验:
- ctrl+z:撤销上一次的操作
按下ctrl+z时, textChanged , undoAvailable , redoAvailable , cursorPositionChanged 会触发
首先我们需要当前撤销栈和重做栈的状态
撤销栈:[输入1, 输入2, 输入3] (栈顶是输入3)
重做栈:[]
我们按下ctrl+z
我们发现这里触发了[redoAvailable] true,这是为什么呢?
因为我们执行了一次撤销操作(ctrl+z),这个时候我们的重做栈中有了操作记录,从无记录变成了有记录,状态发生改变,这时重做变为可用,会触发redoAvailable(true)。注意,只要重做栈从空变为非空,就会触发。
不过大家也需要注意,一次撤销操作会使得撤销栈失去一条操作记录。但是失去了一条操作记录,仍然不会改变这个撤销栈的状态——有记录,所以不会触发undoAvailable(false)
现在
撤销栈:[输入1, 输入2] (栈顶是输入2)
重做栈:[输入3]
我们接着ctrl+z
因为我们执行了一次撤销操作(ctrl+z),这个时候我们的重做栈中又多了一条操作记录(但是状态还是不变——有记录),所以不会触发这个redoAvailable()
不过大家也需要注意,一次撤销操作会使得撤销栈失去一条操作记录。但是失去了一条操作记录,仍然不会改变这个撤销栈的状态——有记录,所以不会触发undoAvailable(false)
撤销栈:[输入1]
重做栈:[输入3,输入2](栈顶是输入2)
我们接着ctrl+z
我们发现这个触发了[undoAvailable] false,这又是为什么呢?
因为我们执行了一次撤销操作(ctrl+z),这个时候我们的重做栈中又多了一条操作记录(但是状态还是不变——有记录),所以不会触发这个redoAvailable()
不过大家也需要注意,一次撤销操作会使得撤销栈失去一条操作记录。注意了,我们这里失去了一条操作记录,会改变这个撤销栈的状态——从有记录到无记录,所以会触发undoAvailable(false)
撤销栈:[]
重做栈:[输入3,输入2,输入1](栈顶是输入1)
我们点击ctrl+y
我们发现这个触发了[undoAvailable] true,这又是为什么呢?
因为我们执行了一次重做操作(ctrl+y),这个时候我们的重做栈中少了一条操作记录(但是状态还是不变——有记录),所以不会触发这个redoAvailable()
不过大家也需要注意,一次重做操作(ctrl+y)会使得撤销栈增加一条操作记录。注意了,我们这里增加了一条操作记录,会改变这个撤销栈的状态——从无记录到有记录,所以会触发undoAvailable(true)
撤销栈:[输入1]
重做栈:[输入3,输入2](栈顶是输入2)
我们按ctrl+y
我们执行了一次重做操作(ctrl+y),这个时候我们的重做栈中少了一条操作记录(但是状态还是不变——有记录),所以不会触发这个redoAvailable()
不过大家也需要注意,一次重做操作(ctrl+y)会使得撤销栈增加一条操作记录。注意了,我们这里增加了一条操作记录,不会改变这个撤销栈的状态——有记录,所以不会会触发undoAvailable()
撤销栈:[输入1,输入2] (栈顶是输入2)
重做栈:[输入3]
我们按ctrl+y
我们发现这里又触发了一次[redoAvailable] false,这是为啥呢?
我们执行了一次重做操作(ctrl+y),这个时候我们的重做栈中少了一条操作记录,但是状态变化了——从有操作记录到没有操作记录,所以会触发这个redoAvailable(false).
不过大家也需要注意,一次重做操作(ctrl+y)会使得撤销栈增加一条操作记录。注意了,我们这里增加了一条操作记录,不会改变这个撤销栈的状态——有记录,所以不会会触发undoAvailable()
撤销栈:[输入1,输入2,输入3] (栈顶是输入3)
重做栈:[]
怎么样?彻底弄懂了没??
2.3.示例1——获取多⾏输⼊框的内容
1) 创建⼀个多⾏输⼊框和⼀个label
2) 给多⾏输⼊框添加slot函数.处理textChanged 信号.
- 通过toPlainText ⽅法获取到内部的⽂本.
- 类似的, QTextEdit 还提供了toMarkdown 和toHtml .根据需要我们调整不同的获取⽅式.
我们运行一下
3) 执⾏程序,可以看到当输⼊框中的内容发⽣变化时,label中的内容同步发⽣改变
三. ComboBox
QComboBox 表⽰下拉框
3.1.核心属性
1. currentText
-
含义: 当前显示的文本。
-
详细说明:
-
这个属性反映了组合框输入区域(即用户能看到的那一行)当前显示的文字内容。
-
它的值取决于
editable
属性和用户的操作:-
如果组合框是不可编辑的(
editable
为false
):currentText
的值完全由当前选中的条目(currentIndex
)决定。用户只能通过下拉列表选择已有的项,此时currentText
就是被选中项的文字。 -
如果组合框是可编辑的(
editable
为true
):currentText
的值可以是用户直接在该行输入框中键入的任何文本,而不一定是下拉列表中的某个现有项。当然,用户也可以从下拉列表中选择一个项,此时currentText
会自动设置为该选项的文字。
-
-
-
用途: 这是你最常用来获取用户最终输入或选择结果的属性。例如,当用户点击“确定”按钮后,你可以通过读取
comboBox.currentText()
来知道用户想要什么。
2. currentIndex
-
含义: 当前选中的条目在下拉列表中的索引(位置编号)。
-
详细说明:
-
索引是从
0
开始计算的。列表中的第一个条目的索引是0
,第二个是1
,以此类推。 -
这是一个非常重要的“哨兵值”(或称为“魔数”),用于表示一种特殊状态:当没有任何条目被选中时,
currentIndex
的值是-1
。这种情况通常发生在:-
组合框刚被创建,还没有任何选项,也没有设置默认选项。
-
程序代码主动将
currentIndex
设置为-1
,以清空选择。 -
组合框是可编辑的,用户输入了一个不存在于下拉列表中的全新文本。
-
-
currentIndex
和currentText
是紧密关联的。当currentIndex
是一个有效的非负整数(如0, 1, 2...
)时,currentText
就是对应索引的条目的文本。
-
-
用途:
-
当你更关心用户选择了第几个选项,而不是选项的具体文字时(例如,选项的文字可能会被翻译,但索引是固定的),这个属性就非常有用。
-
通过将其设置为
-1
可以清空组合框的选中状态。
-
3. editable
-
含义: 布尔值属性,控制用户是否可以直接在组合框的输入框中编辑文本。
-
详细说明:
-
当设置为
false
(默认值)时,组合框的行为像一个传统的下拉列表。用户只能点击下拉箭头,然后从预设的选项中选择一个。他们不能修改输入框里的文字。 -
当设置为
true
时,组合框的行为就非常接近QLineEdit
(单行输入框),但同时它又具备一个下拉列表,提供常用的预设选项供用户快速选择。用户既可以自由输入任何文本,也可以从列表中选择。
-
-
用途: 当你需要为用户提供一些建议选项,但又不限制他们只能使用这些选项,允许他们输入自定义内容时,就将此属性设为
true
。例如,浏览器中的地址栏就是一个典型的可编辑组合框。
4. validator
-
含义: 输入验证器。当组合框处于可编辑状态时,用于限制或验证用户输入的内容。
-
详细说明:
-
这个属性只有在
editable
为true
时才有效。对于不可编辑的组合框,设置验证器没有意义。 -
你可以设置不同的验证器来确保用户输入的数据是有效的,例如:
-
QIntValidator
: 限制只能输入整数(如100
,-5
)。 -
QDoubleValidator
: 限制只能输入浮点数(如3.14
,-0.5
)。 -
QRegExpValidator
或QRegularExpressionValidator
: 使用正则表达式来定义复杂的输入规则(如只允许输入邮箱格式的文本、特定格式的电话号码等)。 -
这个我们在讲QLineEdit的时候就讲过了。
-
-
当用户的输入不符合验证规则时,输入框的边框可能会变红,或者输入本身会被阻止/修正,这取决于验证器的具体配置。
-
-
用途: 在可编辑的组合框中,确保用户输入的数据是符合程序要求的、格式正确的,避免无效或危险的数据输入。
5. iconSize
-
含义: 图标的大小。
-
详细说明:
-
这个属性主要控制组合框中两个地方的图标尺寸:
-
下拉列表中的条目图标:如果你使用
addItem(icon, text)
这样的方法为每个选项添加了图标,那么这个属性会控制这些图标在列表中的显示大小。 -
下拉按钮本身的图标:即组合框右侧那个小小的下拉箭头(小三⻆)。这个属性也会影响这个箭头图标的大小。
-
-
它是一个
QSize
对象,你需要指定宽度和高度(例如QSize(16, 16)
)。
-
-
用途: 用于统一调整组合框内所有图标的视觉大小,使其与整体界面风格保持一致。
6. maxCount
-
含义: 组合框的下拉列表中最多允许拥有的条目数量。
-
详细说明:
-
这是一个上限限制。当你尝试通过
addItem()
,insertItem()
,addItems()
等方法添加的条目总数超过maxCount
时,超出的部分将不会被添加。 -
默认情况下,这个值通常是一个很大的数(如
32767
),意味着基本没有限制。 -
这个属性对于性能优化和防止界面失控非常有用。如果一个组合框可能有成千上万个选项(比如从数据库里读取的所有城市名),无限制地加载会导致程序初始化缓慢,并且下拉列表会变得非常长,难以操作。这时,你可以结合其他技术(如动态搜索、分页加载),并用
maxCount
来限制一次性显示的数量。
-
-
用途: 限制下拉列表的长度,提升用户体验和程序性能。
3.2.核心方法
核心比喻:把 QComboBox 当作一个“点餐菜单”
想象一下,你走进一家奶茶店,面前有一个菜单板,这个菜单板就是 QComboBox
。
-
菜单板本身:就是
QComboBox
这个控件。 -
菜单上的每一项(比如“珍珠奶茶”、“芋圆奶茶”、“茉莉绿茶”)就是一个个“条⽬”(Item)。
-
当前被选中的那一项:就是你用手指着或者店员高亮显示的那一款奶茶。
现在,我们来看这三个方法分别对应什么操作。
方法一:addItem(const QString&)
-
中文意思:添加项⽬
-
参数:
const QString&
-> 一个文本字符串,就是你想要添加的条目的名字。 -
返回值:无(
void
类型)。 -
用“点餐菜单”来理解:
这个方法就是老板往菜单板上添加新饮品的动作。
比如,店里新推出了一款“黑糖奶茶”,老板就会执行addItem(“黑糖奶茶”)
这个操作。于是,菜单板上就多了一个选项。 -
在程序中的作用:
这个方法用于动态地向一个下拉列表框中添加新的选项。程序刚开始运行时,列表框可能是空的,你可以通过多次调用addItem
来把需要的选项一个个加进去。-
comboBox->addItem(“北京”);
// 菜单上加了“北京” -
comboBox->addItem(“上海”);
// 菜单上又加了“上海” -
comboBox->addItem(“广州”);
// 菜单上又加了“广州”
-
小结:addItem
就是“做加法”,负责给列表增加新的选择。
方法二:currentIndex()
-
中文意思:当前下标 / 当前索引
-
参数:无。
-
返回值:一个整数(
int
)。 -
用“点餐菜单”来理解:
这个方法就是问你:“你现在选的是菜单上的第几个?”
关键是,菜单的排序是从 0 开始数的,而不是从 1 开始。-
第一个选项(比如“珍珠奶茶”)的下标是 0。
-
第二个选项(比如“芋圆奶茶”)的下标是 1。
-
第三个选项(比如“茉莉绿茶”)的下标是 2。
如果你还没有做任何选择,或者菜单上一个选项都没有,那么这个方法就会返回 -1。
-
-
在程序中的作用:
这个方法非常有用,因为它返回的是一个数字编号。计算机非常擅长处理数字,我们可以根据这个编号去做很多逻辑判断。-
如果
comboBox->currentIndex() == 0
,说明用户选中了第一个选项。 -
如果
comboBox->currentIndex() == -1
,说明当前没有任何选中项(比如列表是空的)。
-
小结:currentIndex
就是“问位置”,返回当前选中的是第几个选项(从0开始数),没选就返回-1。
方法三:currentText()
-
中文意思:当前⽂本
-
参数:无。
-
返回值:一个字符串(
QString
)。 -
用“点餐菜单”来理解:
这个方法就是直接问你:“你现在选的奶茶叫什么名字?”
它不关心是第几个,只关心最终的名字是什么。-
如果你选了“珍珠奶茶”,它就返回
“珍珠奶茶”
。 -
如果你选了“茉莉绿茶”,它就返回
“茉莉绿茶”
。
如果当前没有选择任何项,它会返回一个空的字符串(""
),就像你什么都没说一样。
-
-
在程序中的作用:
当你需要直接知道用户选择的文字内容时,就用这个方法。比如,用户在一个城市选择框里选了一个城市,你可以直接用currentText()
拿到这个城市的名字,然后去数据库里查询这个城市的天气。-
QString city = comboBox->currentText();
// 假设用户选了“上海”,city 的值就是 “上海”
-
小结:currentText
就是“问名字”,直接返回当前选中项的文本内容,没选就返回空字符串。
3.3.核心信号
1. activated(int index) 和 activated(const QString &text)
-
本质:这两个是同一个信号的重载版本,一个传递索引号(int),一个传递选项的文本(QString)。它们在同一时刻被触发。
-
触发时机:当用户通过交互“激活”了下拉框中的某一个选项时。
这里的“激活”是关键,它指的是:
-
用户用鼠标点击下拉框中的某个选项。
-
用户通过键盘上下键导航到某个选项,然后按 回车键(Enter) 确认。
-
重要区别:
-
仅仅用鼠标在高亮选项上划过(hover)是不会触发
activated
信号的。必须有一个“确认”动作(点击或按回车)。 -
activated
信号只在由用户交互引发时才会触发。如果你在代码中通过setCurrentIndex(...)
来改变当前选项,它是不会触发activated
信号的。
-
-
典型应用场景:当你希望一个动作仅在用户明确选择后才发生。例如,选择一个省份后,立即去加载对应的城市列表。
示例:
假设下拉框有选项:["苹果", "香蕉", "橘子"]
-
用户点击下拉框,鼠标移动到“香蕉”上并点击。
-
触发
activated(1)
和activated("香蕉")
信号。
2. currentIndexChanged(int index) 和 currentIndexChanged(const QString &text)
-
本质:同样是重载信号,一个传递索引,一个传递文本。
-
触发时机:当下拉框的当前选项索引发生改变时。这是最根本的变化。
关键在于,它触发的条件非常广泛:
-
用户交互:用户通过点击或键盘回车激活一个选项(此时会先触发
activated
,紧接着触发currentIndexChanged
)。 -
编程改变:你在代码中调用
setCurrentIndex(...)
或setCurrentText(...)
方法来改变当前选项。
-
核心区别:
-
与
activated
相比,currentIndexChanged
是 “结果导向” 的。它不关心改变是怎么发生的(用户操作还是代码设置),只关心“当前选中的项变了”这个事实。 -
因此,它的使用范围比
activated
更广。
-
-
典型应用场景:
-
需要同步界面状态。例如,当下拉框选项改变时,更新另一个标签的显示内容。无论这个改变是用户造成的,还是程序初始化时设置的,你都需要响应。
-
记录或响应任何形式的索引变化。
-
示例:
-
用户操作:用户点击选择了“香蕉”,会先触发
activated
信号,然后立即触发currentIndexChanged(1)
。 -
代码操作:程序启动时,你执行
comboBox->setCurrentIndex(0);
来设置默认选项,这会直接触发currentIndexChanged(0)
,但不会触发activated
。
3. editTextChanged(const QString &text)
-
前提条件:必须将 QComboBox 设置为可编辑的。即在设计器里勾选
editable
属性,或在代码中调用setEditable(true)
。 -
触发时机:当可编辑下拉框的编辑框内的文本内容发生任何改变时。
这里的“改变”包括:
-
用户直接键盘输入。
-
用户粘贴文本。
-
用户删除文本。
-
甚至通过代码调用
setEditText(...)
方法设置文本时也会触发。
-
重要特点:实时性。每输入或删除一个字符,它都会立即触发。
-
典型应用场景:
-
实时搜索/自动完成:用户输入时,动态过滤一个很长的列表。
-
输入验证:实时检查用户输入的内容是否合法。
-
示例:
下拉框是可编辑的,当前文本是空。
-
用户输入字母 “a”。
-
触发
editTextChanged("a")
。 -
用户继续输入 “p”,变成 “ap”。
-
触发
editTextChanged("ap")
。
3.4.示例1——使用下拉框模拟麦当劳点餐
我们先创建一个新项目
1) 在界⾯上创建三个下拉框,3个Label,和⼀个按钮.
2) 编写widget.cpp,初始化三个下拉框的内容,给按钮添加slot函数
我们运行一下
发现它默认就是第一个,我们点击确认
当然我们可以通过下拉列表来切换
点击确认
3.5.示例2——从文件中加载下拉框的选项
很多时候下拉框的选项并⾮是固定的,⽽是通过读取⽂件/读取⽹络获取到的.
我们先创建一个新的项目
1) 在界⾯上创建⼀个下拉框和一个QLabel
接着,我们创建一个文件,把下面这段文字粘贴进去
小明
小红
小蓝
小兰
小叶
小红
这个文件的路径是"D:\Qt\project\test41\test.txt",注意了啊,我们在代码里面应该写成D:/Qt/project/test41/test.txt
接下来我们就来写一下我们的代码
怎么样?还是很可以的吧。