当前位置: 首页 > news >正文

【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()
  • 说明:当用户"完成编辑"这一动作时发出。

  • 详细解释

    • 触发时机:这是一个"复合"触发信号,在以下任一情况发生时都会触发:

      1. 用户按下 返回键 或 Enter 键。

      2. 行编辑框失去焦点(例如用户点击了界面上其他控件)。

    • 它表示用户可能已经输入完毕,准备进行下一步操作。

  • 典型用途

    • 表单提交:在输入完一个字段后,自动验证或保存数据,而不必等用户点击"提交"按钮。

    • 实时搜索:当用户在搜索框中输入完毕(比如移开光标或按回车)后,立即开始搜索。相比于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 提供了两个主要的类来处理正则表达式,它们代表了两个不同的时代:

  1. QRegExp:这是 Qt 早期版本(Qt 1.x 到 Qt 4.x)中使用的传统正则表达式引擎。

  2. QRegularExpression:这是从 Qt 5.0 开始引入的现代正则表达式引擎。目前(Qt 5 和 Qt 6 时代),QRegularExpression 是官方推荐使用的类

在接下来的例子中,我将使用QRegularExpression来演示


1.4.2.Qt内置验证器对象

Qt中内置了四个主要的验证器对象。

它们都是QValidator的子类

那么我们就先讲讲这个QValidator

一、QValidator 是什么?—— 给它一个形象的角色

你可以把 QValidator 想象成一位严格而又聪明的「输入质检员」

它的工作岗位,就是守在文本框、输入框这类需要用户输入内容的地方。每当用户通过键盘输入一个字符,这位「质检员」就会立刻介入,判断这个新输入的字符,或者当前整个输入的内容,是否符合你(程序员)预先设定好的「质量标准」。

它的核心任务不是等用户全部输完了再报错,而是在输入的过程中就进行实时监督和引导,确保最终得到的数据是干净、合规的。

二、QValidator 的核心工作原则:三种判定状态

这位「质检员」在工作中,对任何输入内容只会做出以下三种判定。理解这三种状态是理解 QValidator 的关键:

  1. 「合格」(QValidator::Acceptable

    • 含义:当前输入框中的内容完全符合所有规则,是完美无缺的。

    • 比喻:就像你填写一份表格,所有必填项都填了,格式也完全正确(比如身份证号正好是18位)。质检员会亮起绿灯。

    • 在程序中的表现:输入框通常显示为正常的样式(比如白色背景),程序可以安全地读取并使用这个数据。

  2. 「待定」(QValidator::Intermediate

    • 含义:当前的内容还不完整或不完全符合规则,但它有「潜力」通过继续输入变成「合格」的。这是一个非常有用且人性化的状态。

    • 比喻:最典型的例子是输入手机号。规则是11位数字。当你只输入了前3位(如“139”)时,它虽然不完整,但方向是正确的,没有错误。质检员会亮起黄灯,意思是“请继续,但还没完成”。

    • 在程序中的表现:输入框可能会显示一个温和的提示(比如淡黄色背景),告诉用户需要继续输入。程序不应该使用这个状态下的数据。

  3. 「不合格」(QValidator::Invalid

    • 含义:当前输入的内容(尤其是刚输入的字符)根本违反了核心规则,并且无论如何继续输入,它都不可能变成「合格」。

    • 比喻:同样在只能输入数字的框里,你试图输入一个字母“A”。这个“A”本身就是非法的。质检员会立刻亮起红灯,并常常会拒绝这个字符进入输入框

    • 在程序中的表现:输入框可能会变成醒目的警告色(如红色),或者最常见的是,那个非法的字符根本就输不进去,你按键后会发现输入框没有任何变化。

简单总结三态关系

  • 合格:完美,可用。

  • 待定:不完美,但允许你继续朝着完美的方向努力。

  • 不合格:错误,且不允许存在。

我们可以去代码里面看看是什么样子的:

三、常用的几种「质检员」(内置验证器类型)

Qt 为我们提供了几种现成的、具有不同专业技能的「质检员」:

  1. 整数质检员(QIntValidator)

    • 专业技能:只允许输入整数,并且可以规定这个整数的范围(例如,从 0 到 150)。

    • 工作场景:适合用来检查「年龄」、「数量」等。

    • 如何工作:你告诉他:“只允许检查 0 到 150 之间的整数。” 然后他上岗。用户输入“50”,他判「合格」;输入“2”,他判「待定」(因为可能想输入“25”);输入“abc”或“200”,他判「不合格」。

  2. 浮点数字检员(QDoubleValidator)

    • 专业技能:允许输入小数。可以规定数值范围和小数点后的位数。

    • 工作场景:适合用来检查「身高」、「体重」、「价格」等。

    • 如何工作:你告诉他:“只允许检查 0.5 到 2.5 之间,且最多一位小数。” 用户输入“1.7”,判「合格」;输入“1.”(只输入了小数点),判「待定」(用户可能正要输入小数部分);输入“3.0”或“1.2a”,判「不合格」。

  3. 万能正则表达式质检员(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 方法的两个参数:

  1. 第一个参数(QString& input):

    • 作用:这是你要交给质检员检查的"文本样品"。也就是你想判断是否合规的那段字符串。

    • QString& 的含义:这里的 & 符号表示这是一个"引用"。通俗地讲,质检员收到的不是一份文本的"复印件",而是"原件"本身。这意味着,理论上质检员有权直接修改你交给他的这份文本(比如,自动帮你格式化:删除空格、纠正大小写等)。这就是为什么注释里说,如果你不想让原文本被修改,需要先复制一份再传给它。你把原件给了它,它可能会在上面涂改。

    • 这就是我们为啥已经有了arg1,然后还需要创建一个新的临时变量

      QString content = arg1;,然后再将content传进去的原因

  2. 第二个参数(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)

这些属性决定了输入框里能放什么内容,以及内容如何被处理和显示。

  1. markdown

    • 含义:输入框内存储的原始文本内容,这个内容是使用 Markdown 语法 编写的。

    • 详细解释:Markdown 是一种轻量级标记语言,用简单的符号(如 # 表示标题,**粗体** 表示加粗)来定义格式。这个属性值就是用户输入的这些带标记的纯文本。它的强大之处在于,编辑器能够自动将这些 Markdown 文本实时渲染成美观的、格式化的 HTML 内容(见下一个属性 html)供用户阅读。非常适合需要兼顾“方便写作”和“美观显示”的场景,比如写博客、笔记等。

  2. html

    • 含义:由 Markdown 内容自动渲染后生成的,或用户直接输入的 HTML 代码

    • 详细解释:这是最终呈现给用户看的、经过格式化的内容。它支持大部分 HTML 标签,这意味着你可以在里面插入图片 (<img>)、创建复杂的表格 (<table>)、添加链接等,实现非常丰富的排版效果。通常,markdown 和 html 这两个属性是关联的:用户编辑 markdown,程序自动更新 html。但在某些模式下,也可能允许用户直接编辑 html 代码。

  3. acceptRichText

    • 含义:控制输入框是否接收和显示富文本内容

    • 详细解释:这是一个总开关。如果设置为 false(关闭),那么输入框将只接受纯文本。即使用户从其他网页或Word文档中复制了带有格式(如字体、颜色、加粗)的内容粘贴进来,这些格式也会被自动剥离,只留下纯文字。如果设置为 true(开启),则粘贴或输入的内容可以保留其原有的富文本格式。这个功能可以防止格式混乱。

  4. autoFormating

    • 含义:是否开启自动格式化

    • 详细解释:这是一个提升写作体验的功能。开启后,编辑器会在你输入时自动帮你完成一些格式调整。例如,自动将直引号 " " 转换为更美观的弯引号 “ ”,或者自动将网络地址和邮箱地址转换为可点击的链接。它让你专注于内容,而不用操心一些琐碎的格式细节。

第二类:行为与交互 (Behavior & Interaction)

这些属性控制了用户如何与输入框进行交互。

  1. readOnly

    • 含义:输入框是否为只读模式

    • 详细解释:如果设置为 true(是),那么用户将无法对输入框内的内容进行任何修改、删除或添加。它看起来和正常输入框一样,但光标无法聚焦或无法输入。这个模式常用于显示文档、说明、代码等,让用户只能阅读而不能编辑。

  2. undoRedoEnable

    • 含义:是否开启撤销 (Undo) 和重做 (Redo) 功能

    • 详细解释:这是文本编辑中至关重要的功能。开启后,系统会记录你的每一步操作。

      • 撤销 (Undo):当你误操作(如误删一大段文字)时,可以按下 Ctrl + Z 来撤销上一步操作,恢复到之前的状态。

      • 重做 (Redo):如果你撤销了某一步但又反悔了,可以按下 Ctrl + Y,将刚刚撤销的操作重新执行。
        这相当于为你的编辑工作提供了“后悔药”。

  3. overwriteMode

    • 含义:是否开启覆盖写模式(也叫“改写模式”)。

    • 详细解释:我们通常的输入模式是“插入模式”,即你在两个字中间输入新字,原来的字会向后移动。而“覆盖模式”下,你在两个字中间输入新字,新字会直接覆盖掉光标后面的那个字。这个功能在某些特定的表格数据录入场景下有用,但日常写作中较少使用。

  4. tabstopWidth

    • 含义:按下 Tab 键时,缩进所占的空格宽度

    • 详细解释:在编写代码或需要层级结构的文本时,我们常用 Tab 键来缩进。这个属性就是用来定义一次 Tab 缩进相当于多少个空格的宽度。例如,通常编程时会设置为 4,表示按一次 Tab 键,就插入相当于 4 个空格的缩进量。

第三类:视觉与提示 (Visual & Hint)

这些属性关乎输入框的外观和给用户的提示。

  1. 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,它的意思是:取消最近一次的操作,将文档恢复到该操作之前的状态。

举个例子:

  1. 你打开一个空文档,输入了字母"A",现在文档内容是"A"。

  2. 你觉得自己输错了,按下Ctrl+Z,那么这次输入操作被撤销,文档内容又变回空。

撤销功能可以连续进行,也就是说,你可以一步一步地撤销之前的多个操作,直到恢复到文档的初始状态(或者直到撤销栈为空)。

重做(Redo)的含义

重做,通常对应快捷键 Ctrl+Y 或 Ctrl+Shift+Z,它的意思是:重新执行最近一次被撤销的操作,将文档恢复到撤销操作之前的状态。

继续上面的例子:

  1. 你输入"A"后,按Ctrl+Z撤销了,文档变空。

  2. 但你突然又觉得那个"A"是对的,于是按下Ctrl+Y,那么被撤销的输入操作被重新执行,文档内容又变回"A"。

重做功能只能在撤销之后使用,而且只能按撤销的顺序反向重新执行操作。如果你在撤销之后又进行了新的操作,那么重做栈会被清空,也就是说你不能重做在新操作之前被撤销的那些操作了。

工作原理简述

编辑器内部会维护两个栈(或历史记录列表):

  • 撤销栈(Undo Stack):保存用户执行过的操作(如输入、删除等),每个操作都包含足够的信息来撤销它。

  • 重做栈(Redo Stack):保存被撤销的操作,以便可以重做。

当用户执行一个操作时:

  • 这个操作会被记录到撤销栈中,同时重做栈会被清空(因为新的操作改变了文档状态,重做栈中的操作已经不再适用)。

当用户执行撤销时:

  • 从撤销栈中弹出最近的操作,并执行该操作的逆向操作(即撤销它),然后把这个操作放入重做栈

当用户执行重做时:

  • 从重做栈中弹出最近被撤销的操作,并执行它(即重做),然后把这个操作放回撤销栈。

重要特性

  1. 线性操作:撤销和重做是严格按顺序的,你不能跳过中间步骤去撤销一个更早的操作。

  2. 分支清除:一旦在撤销后执行了新的操作,重做栈就会被清空。这意味着你不能再重做那些被清除的操作。这就像你走到一个岔路口选择了一条新路,就不能再走另一条路了。

  3. 操作粒度:有时一个操作可能包含多个子操作(比如自动更正可能会替换多个字符),但编辑器通常会将它们作为一个整体来撤销/重做。

实际应用中的例子

假设我们有一个文档,初始为空。

  1. 输入"hello" -> 文档变为"hello",撤销栈记录了这个输入操作。

  2. 输入" world" -> 文档变为"hello world",撤销栈有两个操作。

  3. 按Ctrl+Z(撤销) -> 撤销第二个操作,文档变回"hello",被撤销的操作被移到重做栈。

  4. 按Ctrl+Z(撤销) -> 撤销第一个操作,文档变回空,撤销栈空,重做栈有两个操作(按顺序是输入"hello"和输入" world")。

  5. 按Ctrl+Y(重做) -> 重做栈顶的操作(输入"hello")被重做,文档变为"hello",这个操作被移回撤销栈。

  6. 按Ctrl+Y(重做) -> 重做下一个操作(输入" world"),文档变为"hello world"。

如果在第5步后,我们没有重做第二步,而是输入了"abc":

  • 那么重做栈中"输入 world"的操作会被清空,我们不能再通过重做来得到"hello world"了。


好了,搞明白上面这些东西了,我们现在就可以来讲这些信号了。

4.1. undoAvailable(bool available)

这个信号在“是否可以执行撤销操作”的状态发生变化时触发。具体来说:

  1. 从不可撤销变为可以撤销(available = true):
    当用户执行了一个可以撤销的修改操作(例如:输入一个字符、删除一段文字、粘贴内容等)时,如果之前撤销栈是空的(即之前不能执行撤销),那么现在有了一个操作记录,撤销变为可用,因此会触发undoAvailable(true)。

  2. 从可以撤销变为不可撤销(available = false):
    当用户连续执行撤销操作,直到撤销栈中没有任何操作记录时,就会触发undoAvailable(false)。另外,如果编辑器被清空(例如通过代码设置一个空文本)并且撤销栈被清空,也会触发。

  3. 注意:如果用户进行多个操作,然后执行撤销,但并没有撤销到最开始(即撤销栈中还有操作),那么撤销仍然可用,不会触发undoAvailable(false)。只有当撤销栈为空时,才会触发false。

  4. 特殊情况:如果编辑器被设置为只读(readOnly),那么用户不能编辑,所以通常不会触发undoAvailable(true),因为用户不能进行修改。但是,如果通过程序代码修改文本(例如调用setText),则可能会根据编辑器的设置决定是否记录撤销操作。

  5. 非用户操作:通过代码修改编辑器内容时,如果这个修改被记录到撤销栈(取决于编辑器的实现和设置),也会影响撤销状态的可用性,从而触发信号。

4.2.redoAvailable(bool available)

这个信号在“是否可以执行重做操作”的状态发生变化时触发。具体来说:

  1. 从不可重做变为可以重做(available = true):
    当用户执行了一次或多次撤销操作后,重做栈中有了操作记录,这时重做变为可用,会触发redoAvailable(true)。注意,只要重做栈从空变为非空,就会触发。

  2. 从可以重做变为不可重做(available = false):
    当用户执行了重做操作,直到重做栈为空时,会触发redoAvailable(false)。另外,如果用户在撤销后进行了新的编辑操作(即用户没有执行重做,而是输入了新的内容),那么重做栈会被清空(因为新的编辑操作使重做栈中的操作记录变得无效),这时也会触发redoAvailable(false)。

  3. 注意:重做栈的清空时机:当用户在执行了撤销操作后,没有进行重做,而是进行了新的编辑操作,那么重做栈会被清空。这是因为新的编辑操作与重做栈中的操作可能产生冲突,而且线性编辑历史中不能有分叉。

  4. 非用户操作:通过代码执行撤销或重做,或者通过代码修改内容(可能清空重做栈)也会触发相应的信号。

示例场景

假设编辑器初始状态为空,撤销和重做都不可用。

  1. 用户输入字符'A':

    • 撤销栈中记录了这个操作,撤销变为可用:触发undoAvailable(true)。

    • 重做栈为空,重做不可用(不变,不触发信号)。

  2. 用户输入字符'B':

    • 撤销栈中又记录了一个操作,撤销仍然可用(不变,不触发undoAvailable信号)。

    • 重做栈为空,重做不可用(不变)。

  3. 用户按Ctrl+Z(撤销):

    • 撤销栈弹出操作'B',编辑器文本变回"A"。

    • 撤销栈中还有一个操作(操作'A'),所以撤销仍然可用(不变)。

    • 重做栈中压入了操作'B',重做从不可用变为可用:触发redoAvailable(true)。

  4. 用户按Ctrl+Z again(撤销):

    • 撤销栈弹出操作'A',编辑器文本变回空。

    • 撤销栈为空,撤销从可用变为不可用:触发undoAvailable(false)。

    • 重做栈中压入了操作'A',重做栈非空(重做可用,但之前已经可用了,所以不变)。

  5. 用户按Ctrl+Y(重做):

    • 重做栈弹出操作'A',编辑器文本变为"A"。

    • 撤销栈中压入操作'A',撤销从不可用变为可用:触发undoAvailable(true)。

    • 重做栈中还有操作'B'(重做仍然可用,不变)。

  6. 用户按Ctrl+Y again(重做):

    • 重做栈弹出操作'B',编辑器文本变为"AB"。

    • 撤销栈中压入操作'B',撤销可用(不变)。

    • 重做栈为空,重做从可用变为不可用:触发redoAvailable(false)。

  7. 用户输入字符'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)

这个信号在“是否可以执行撤销操作”的状态发生变化时触发。具体来说:

  1. 从不可撤销变为可以撤销(available = true):
    当用户执行了一个可以撤销的修改操作(例如:输入一个字符、删除一段文字、粘贴内容等)时,如果之前撤销栈是空的(即之前不能执行撤销),那么现在有了一个操作记录,撤销变为可用,因此会触发undoAvailable(true)。

  2. 从可以撤销变为不可撤销(available = false):
    当用户连续执行撤销操作,直到撤销栈中没有任何操作记录时,就会触发undoAvailable(false)。另外,如果编辑器被清空(例如通过代码设置一个空文本)并且撤销栈被清空,也会触发。

  3. 注意:如果用户进行多个操作,然后执行撤销,但并没有撤销到最开始(即撤销栈中还有操作),那么撤销仍然可用,不会触发undoAvailable(false)。只有当撤销栈为空时,才会触发false。

  4. 特殊情况:如果编辑器被设置为只读(readOnly),那么用户不能编辑,所以通常不会触发undoAvailable(true),因为用户不能进行修改。但是,如果通过程序代码修改文本(例如调用setText),则可能会根据编辑器的设置决定是否记录撤销操作。

  5. 非用户操作:通过代码修改编辑器内容时,如果这个修改被记录到撤销栈(取决于编辑器的实现和设置),也会影响撤销状态的可用性,从而触发信号。

3.redoAvailable(bool available)

这个信号在“是否可以执行重做操作”的状态发生变化时触发。具体来说:

  1. 从不可重做变为可以重做(available = true):
    当用户执行了一次或多次撤销操作后,重做栈中有了操作记录,这时重做变为可用,会触发redoAvailable(true)。注意,只要重做栈从空变为非空,就会触发。

  2. 从可以重做变为不可重做(available = false):
    当用户执行了重做操作,直到重做栈为空时,会触发redoAvailable(false)。另外,如果用户在撤销后进行了新的编辑操作(即用户没有执行重做,而是输入了新的内容),那么重做栈会被清空(因为新的编辑操作使重做栈中的操作记录变得无效),这时也会触发redoAvailable(false)。

  3. 注意:重做栈的清空时机:当用户在执行了撤销操作后,没有进行重做,而是进行了新的编辑操作,那么重做栈会被清空。这是因为新的编辑操作与重做栈中的操作可能产生冲突,而且线性编辑历史中不能有分叉。

  4. 非用户操作:通过代码执行撤销或重做,或者通过代码修改内容(可能清空重做栈)也会触发相应的信号。

    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

    • 含义: 图标的大小。

    • 详细说明

      • 这个属性主要控制组合框中两个地方的图标尺寸:

        1. 下拉列表中的条目图标:如果你使用 addItem(icon, text) 这样的方法为每个选项添加了图标,那么这个属性会控制这些图标在列表中的显示大小。

        2. 下拉按钮本身的图标:即组合框右侧那个小小的下拉箭头(小三⻆)。这个属性也会影响这个箭头图标的大小。

      • 它是一个 QSize 对象,你需要指定宽度和高度(例如 QSize(16, 16))。

    • 用途: 用于统一调整组合框内所有图标的视觉大小,使其与整体界面风格保持一致。

    6. maxCount

    • 含义: 组合框的下拉列表中最多允许拥有的条目数量

    • 详细说明

      • 这是一个上限限制。当你尝试通过 addItem()insertItem()addItems() 等方法添加的条目总数超过 maxCount 时,超出的部分将不会被添加

      • 默认情况下,这个值通常是一个很大的数(如 32767),意味着基本没有限制。

      • 这个属性对于性能优化防止界面失控非常有用。如果一个组合框可能有成千上万个选项(比如从数据库里读取的所有城市名),无限制地加载会导致程序初始化缓慢,并且下拉列表会变得非常长,难以操作。这时,你可以结合其他技术(如动态搜索、分页加载),并用 maxCount 来限制一次性显示的数量。

    • 用途: 限制下拉列表的长度,提升用户体验和程序性能。

    3.2.核心方法

    核心比喻:把 QComboBox 当作一个“点餐菜单”

    想象一下,你走进一家奶茶店,面前有一个菜单板,这个菜单板就是 QComboBox

    1. 菜单板本身:就是 QComboBox 这个控件。

    2. 菜单上的每一项(比如“珍珠奶茶”、“芋圆奶茶”、“茉莉绿茶”)就是一个个“条⽬”(Item)。

    3. 当前被选中的那一项:就是你用手指着或者店员高亮显示的那一款奶茶。

    现在,我们来看这三个方法分别对应什么操作。

    方法一: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)。它们在同一时刻被触发。

    • 触发时机当用户通过交互“激活”了下拉框中的某一个选项时

    这里的“激活”是关键,它指的是:

    1. 用户用鼠标点击下拉框中的某个选项。

    2. 用户通过键盘上下键导航到某个选项,然后按 回车键(Enter) 确认。

    • 重要区别

      • 仅仅用鼠标在高亮选项上划过(hover)是不会触发 activated 信号的。必须有一个“确认”动作(点击或按回车)。

      • activated 信号只在由用户交互引发时才会触发。如果你在代码中通过 setCurrentIndex(...) 来改变当前选项,它是不会触发 activated 信号的。

    • 典型应用场景:当你希望一个动作仅在用户明确选择后才发生。例如,选择一个省份后,立即去加载对应的城市列表。

    示例:

    假设下拉框有选项:["苹果", "香蕉", "橘子"]

    1. 用户点击下拉框,鼠标移动到“香蕉”上并点击。

    2. 触发 activated(1) 和 activated("香蕉") 信号。


    2. currentIndexChanged(int index) 和 currentIndexChanged(const QString &text)

    • 本质:同样是重载信号,一个传递索引,一个传递文本。

    • 触发时机当下拉框的当前选项索引发生改变时。这是最根本的变化。

    关键在于,它触发的条件非常广泛:

    1. 用户交互:用户通过点击或键盘回车激活一个选项(此时会先触发 activated,紧接着触发 currentIndexChanged)。

    2. 编程改变:你在代码中调用 setCurrentIndex(...) 或 setCurrentText(...) 方法来改变当前选项。

    • 核心区别

      • 与 activated 相比,currentIndexChanged 是 “结果导向” 的。它不关心改变是怎么发生的(用户操作还是代码设置),只关心“当前选中的项变了”这个事实。

      • 因此,它的使用范围比 activated 更广。

    • 典型应用场景

      • 需要同步界面状态。例如,当下拉框选项改变时,更新另一个标签的显示内容。无论这个改变是用户造成的,还是程序初始化时设置的,你都需要响应。

      • 记录或响应任何形式的索引变化。

    示例:

    1. 用户操作:用户点击选择了“香蕉”,会先触发 activated 信号,然后立即触发 currentIndexChanged(1)

    2. 代码操作:程序启动时,你执行 comboBox->setCurrentIndex(0); 来设置默认选项,这会直接触发 currentIndexChanged(0),但不会触发 activated


    3. editTextChanged(const QString &text)

    • 前提条件必须将 QComboBox 设置为可编辑的。即在设计器里勾选 editable 属性,或在代码中调用 setEditable(true)

    • 触发时机当可编辑下拉框的编辑框内的文本内容发生任何改变时

    这里的“改变”包括:

    1. 用户直接键盘输入。

    2. 用户粘贴文本。

    3. 用户删除文本。

    4. 甚至通过代码调用 setEditText(...) 方法设置文本时也会触发。

    • 重要特点实时性。每输入或删除一个字符,它都会立即触发。

    • 典型应用场景

      • 实时搜索/自动完成:用户输入时,动态过滤一个很长的列表。

      • 输入验证:实时检查用户输入的内容是否合法。

    示例:

    下拉框是可编辑的,当前文本是空。

    1. 用户输入字母 “a”。

    2. 触发 editTextChanged("a")

    3. 用户继续输入 “p”,变成 “ap”。

    4. 触发 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

    接下来我们就来写一下我们的代码

    怎么样?还是很可以的吧。

    http://www.dtcms.com/a/415439.html

    相关文章:

  • 一家专门做内部优惠的网站石柱县建设局网站
  • 网站制作需要什么知识网站的维护和推广
  • 容器主机名解析在香港服务器内部网络的调试方案
  • Facebook相关jsj加密接口
  • 技术支持 鼎维重庆网站建设专家家用电脑可以做网站服务器
  • 网站建设七点二维码制作网站有哪些
  • [创业之路-607]:半导体行业供应链 - 采矿/化工 - 稀有和关键金属
  • 【OpenHarmony实战】系统参数SystemParameter完全指南:param get/set调试技巧与案例精解
  • 大型网站的空间广州营销型网站建设公司哪家名气大
  • 网站本地被劫要怎么做马上飞做的一些网站
  • 牡丹江做网站公司公司网站维护费大概需要多少
  • 定时/延时消息从RocketMQ 4.x到RocketMQ 5.0的演变:从固定延时等级到精准延时时间
  • 最大似然估计与协方差正则化:从推导到实践
  • 苏宁item_search - 按关键字搜索商品接口深度分析及 Python 实现
  • 企业大型网站建设要多少钱动漫设计作品
  • linux基础服务(2)
  • 学校微网站模板下载企业大学网站建设计划
  • 【华为 ICT HCIA eNSP 习题汇总】——题目集24
  • 广府网站建设学剪辑有必要报班吗
  • 好的企业管理网站瓯网
  • 氛围编程(Vibe Coding)的局限性
  • 台州网站制作套餐建设网站有哪些参考文献
  • 数据集 - LaTeX OCR
  • Java面试-并发面试(一)
  • 比特之绘:位图的二进制诗学
  • 【K8s-Day 32】StatefulSet 深度解析:为你的数据库和有状态应用保驾护航
  • 优质的营销网站建设广告公司取名
  • Webpack5 第四节
  • 设计网站公司力荐亿企邦松江新城投资建设发展有限公司网站
  • 家用电器:从解放双手到智能生活的变革者