开篇介绍:
hello 大家,本篇博客我们来学习QTreeWidget常见属性以及QTreeWidgetItem类。
在 Qt 桌面应用开发中,当我们需要展示和管理 "具有层级关系的数据" 时 ------ 比如文件管理器的目录树、公司的组织架构、电商的商品分类、思维导图的节点结构 ------ 我们就需要一个专门的控件:QTreeWidget(树形控件)。
QTreeWidget 就像 "我们平时用的文件管理器左侧的目录树"------ 它由一个个 "节点" 组成,最上面的节点叫 "顶层节点",顶层节点下面可以有 "子节点",子节点下面还可以有 "子节点的子节点",层层嵌套,形成一棵 "树";你可以点击节点前面的小三角形(展开 / 折叠图标)来显示或隐藏子节点;你可以给每个节点设置文本、图标、字体;你可以点击节点、双击节点、鼠标悬浮在节点上;你可以动态添加顶层节点、给任意节点添加子节点、删除任意节点。
而 QTreeWidget 中的每一个 "节点",都是由 QTreeWidgetItem(树形节点类) 来表示的 ------QTreeWidgetItem 是 QTreeWidget 的最小组成单元,对应树形结构中的单个节点;它的属性和 QListWidgetItem、QTableWidgetItem 非常相似,只不过它支持 "多列文本 / 图标" 展示,还支持 "父子节点层级关系"。
很多新手刚接触 QTreeWidget 和 QTreeWidgetItem 时,会觉得 "层级关系" 有点绕 ------ 毕竟这是一个 "树状结构",不是一维的列表,也不是二维的表格。但别担心!只要你掌握了 QListWidget 和 QTableWidget,学习 QTreeWidget 就会非常轻松,因为它们的核心逻辑是相通的:QListWidgetItem 是 "一维列表的元素",QTableWidgetItem 是 "二维表格的元素",QTreeWidgetItem 是 "树形结构的元素";它们都有 text、icon、font、selected 这些属性,用法几乎一模一样。
这篇文章我会先讲 QTreeWidgetItem 类的核心属性 (text、textAlignment、icon、font、hidden、disabled、expanded、sizeHint、selected),再讲 QTreeWidgetItem 的核心方法 (addChild、childCount、child、takeChild、removeChild、parent),接着讲 QTreeWidget 的核心方法 (clear、addTopLevelItem、topLevelItem、topLevelItemCount、indexOfTopLevelItem、takeTopLevelItem、currentItem、setCurrentItem、setExpanded、setHeaderLabel),最后讲 QTreeWidget 的核心交互信号(currentItemChanged、itemClicked、itemDoubleClicked、itemEntered、itemExpanded、itemCollapsed),最后是综合示例。
话不多说,我们正式开始!
第一章 先搞懂基础:QTreeWidget 和 QTreeWidgetItem 是什么?
在讲具体内容之前,我们必须先搞懂两个最基础、最重要的问题:QTreeWidget 是用来做什么的?QTreeWidgetItem 是用来做什么的?以及,它们和 QTreeView 的关系是什么?
1.1 QTreeWidget 的核心定位
QTreeWidget 是 Qt Widgets 模块中用于展示和管理具有层级关系的二维树形数据的核心通用控件 ------ 它继承自 QTreeView(树形视图),但比 QTreeView 更简单、更易用,因为它内置了 "节点管理" 的功能,不需要你手动实现数据模型(Model)和视图(View)的分离。
通俗理解:QTreeWidget 就像 "一个简化版的文件管理器目录树"------ 它是一个树状的结构,由 "顶层节点" 和 "子节点" 组成;顶层节点是树的 "根"(可以有多个根),子节点是根下面的 "树枝" 和 "树叶";你可以展开 / 折叠节点,查看不同层级的内容;你可以给每个节点设置文本、图标、字体;你可以增加节点、删除节点、选中节点。

QTreeWidget 内置了非常多的功能,不需要你手动实现:
- 它支持设置顶层节点,给顶层节点添加子节点,构建任意深度的树形结构;
- 它支持按 "下标" 精准获取和操作顶层节点,按 "下标" 精准获取和操作任意节点的子节点;
- 它支持获取当前选中的节点,设置选中节点;
- 它支持清空所有节点,删除指定的顶层节点或子节点;
- 它支持自定义表头(列标题),支持多列树形结构;
- 它支持丰富的交互信号:选中变更、点击、双击、鼠标悬浮、展开 / 折叠等;
- 它的样式可以通过 QSS(Qt 样式表)完全自定义。
总之,QTreeWidget 是桌面端 "展示和管理层级关系数据" 场景的通用首选组件------ 只要是想展示一棵树,用 QTreeWidget 就对了。
1.2 QTreeWidgetItem 的核心定位
QTreeWidgetItem 是 Qt 中表示 QTreeWidget 中单个节点的核心类------ 它是 QTreeWidget 的最小组成单元,每个 QTreeWidgetItem 对应树形结构中的单个节点;它支持 "多列文本 / 图标" 展示,核心属性覆盖文本样式、显示状态、交互状态、尺寸定制等维度。
通俗理解:QTreeWidgetItem 就像 "文件管理器目录树里的每一个文件夹或文件"------ 这个文件夹 / 文件可以有名字(text),可以有图标(icon),可以设置字体(font);你可以把它隐藏(hidden),可以把它禁用(disabled),可以把它标记为 "已选中"(selected);如果它是一个文件夹,你可以把它展开(expanded),显示里面的子文件夹 / 文件;你还可以设置它的大小(sizeHint)。
QTreeWidgetItem 的核心特征和 QListWidgetItem、QTableWidgetItem 非常相似,但有两个独特的地方:
- 支持多列展示:每个节点可以有多个列,每个列可以有独立的文本、图标、字体、对齐方式 ------ 就像 "表格的一行",但这一行是在树形结构里的;
- 支持父子层级关系:每个节点可以有父节点(parent),可以有子节点(children)------ 这是构建树形结构的核心。
1.3 QTreeWidget 和 QTreeView 的关系(必知!)
和 QListWidget 与 QListView、QTableWidget 与 QTableView 的关系一样:
- QTreeWidget 是 QTreeView 的子类 ------ 它在 QTreeView 的基础上,内置了一个简单的数据模型(
QStandardItemModel),让你可以直接操作节点,而不需要手动实现 Model/View 架构; - QTreeWidget 比 QTreeView 更简单、更易用------ 如果你只是想展示一个简单的树形结构,不需要复杂的数据模型,用 QTreeWidget 就够了;如果你需要展示大量数据(比如成千上万条节点),或者需要自定义数据模型,再考虑用 QTreeView + 自定义 Model。
1.4 一个超级重要的注意事项(开篇就讲,刻在脑子里!)
在正式开始之前,有一个超级重要、贯穿全文、新手最容易忽略的注意事项,必须开篇就讲,刻在脑子里:
所有与列相关的属性和方法,列号都从 0 开始计数!(超级重要!说三遍!)
默认操作第 0 列;
如果是多列树形结构,必须先通过
QTreeWidget::setColumnCount()设置列数!
通俗理解:就像表格的列号从 0 开始一样,树形节点的列号也是从 0 开始的;第一列是 0,第二列是 1,以此类推;默认情况下,我们只操作第一列(第 0 列)。
这个注意事项超级重要,后面讲每个属性和方法时我还会再强调,但现在必须先记住!
第二章 QTreeWidgetItem 类核心属性详解
好,我们正式开始!按照你提供的顺序,我们首先讲 QTreeWidgetItem 类的核心属性------ 因为要往 QTreeWidget 里放节点,首先得搞懂节点本身怎么设置。QTreeWidgetItem 的属性和 QListWidgetItem、QTableWidgetItem 几乎一模一样,只是多了 "按列设置" 的概念。
2.1 属性一:text------ 树形节点持有的文本内容(按列存储)
2.1.1 属性的核心定义
text 是 QTreeWidgetItem 最核心、最基础的展示属性 ------ 它用于存储和获取节点的文本内容,支持为节点的每一列设置独立文本,默认操作第 0 列;未设置时文本为空字符串,是树形节点最基础的展示内容。
通俗理解:text 就像 "给这个节点起个名字"------ 比如文件管理器里的 "文件夹名""文件名";你可以给这个名字设置不同的列,比如第一列是 "名称",第二列是 "大小",第三列是 "修改时间"。
这里有几个超级重要的规则,必须牢记:
- 列号规则(超级重要!开篇就讲!) :
- 列号从 0 开始,默认操作第 0 列;
- 多列树形需先通过
QTreeWidget::setColumnCount()设置列数;
- 富文本支持 :文本可包含基础 HTML 标签(
<b>/<i>/<font>/<br>等),复杂标签可能无法正常渲染; - 编码适配:支持 UTF-8 编码,可正常显示中文、特殊字符等。
2.1.2 关联 API 详解(逐词逐句,零模糊)
text 属性不是直接访问的,而是通过两个成员函数来设置和获取:
1. 获取指定列的文本:QString text (int column = 0) const
函数原型:
QString QTreeWidgetItem::text(int column = 0) const;
逐词逐句底层解析:
QString:返回值类型,返回文本内容;QTreeWidgetItem:::说明这个函数是QTreeWidgetItem类的成员函数,只能用 QTreeWidgetItem 对象调用;text():函数名,很直观,就是 "获取文本" 的意思;int column = 0:入参,指定要获取哪一列的文本;= 0是默认参数,意思是 "如果你不传参数,默认获取第 0 列的文本";const:常成员函数,不会修改节点状态。
参数说明:
column:要获取文本的列号,int类型,从 0 开始;默认值为 0。
返回值说明:
- 返回
QString类型的文本; - 未设置过文本时返回空字符串(
"")。
2. 设置指定列的文本:void setText (int column = 0, const QString& text)
函数原型:
void QTreeWidgetItem::setText(int column = 0, const QString& text);
逐词逐句底层解析:
void:无返回值;QTreeWidgetItem:::成员函数;setText():函数名,"设置文本" 的意思;int column = 0:入参,指定要设置哪一列的文本,默认第 0 列;const QString& text:入参,要设置的文本内容,const QString&是常量引用,避免拷贝,提高效率。
参数说明:
column:要设置文本的列号,int类型,从 0 开始;默认值为 0;text:要设置的文本内容,QString类型,支持 UTF-8 编码、基础 HTML 标签。
2.1.3 使用示例
#include <QTreeWidgetItem>
#include <QTreeWidget>
// 假设 ui->treeWidget 已经存在
// 示例1:创建树形节点并设置第 0 列文本(单列树形常用)
QTreeWidgetItem* rootItem = new QTreeWidgetItem();
rootItem->setText(0, "根节点"); // 等价于 rootItem->setText("根节点");
ui->treeWidget->addTopLevelItem(rootItem);
// 示例2:多列树形结构:先设置列数,再设置多列文本
ui->treeWidget->setColumnCount(2); // 【必须!】先设置 2 列
QTreeWidgetItem* multiColItem = new QTreeWidgetItem();
multiColItem->setText(0, "名称"); // 第 0 列
multiColItem->setText(1, "描述"); // 第 1 列
ui->treeWidget->addTopLevelItem(multiColItem);
// 示例3:获取节点文本
QString text0 = rootItem->text(0); // 获取第 0 列文本
qDebug() << "第 0 列文本:" << text0;
2.1.4 关键注意事项(必知!)
- 列号从 0 开始!(超级重要!说三遍!);
- 多列树形必须先设置 columnCount!(超级重要!);
- 支持基础 HTML 富文本;
- 默认操作第 0 列。
2.2 属性二:textAlignment------ 树形节点文本的对齐方式(按列设置)
2.2.1 属性的核心定义
textAlignment 是 QTreeWidgetItem 用于控制指定列文本在节点区域内对齐位置 的属性 ------ 它支持水平 + 垂直对齐,默认值为 Qt::AlignLeft | Qt::AlignVCenter(左对齐 + 垂直居中),默认操作第 0 列。
通俗理解:textAlignment 就像 "调整节点里的文字放在什么位置"------ 比如放在左边、右边、中间、上面、下面;默认是 "左边靠中间" 的位置。
这里有几个超级重要的规则,必须牢记:
- 组合使用 :可通过
|(按位或)组合多个对齐方式(如Qt::AlignHCenter | Qt::AlignBottom表示 "水平居中 + 垂直底部对齐"); - 尺寸影响 :节点尺寸过小时,对齐效果不明显,需配合
sizeHint调整; - 图标兼容:图标始终显示在文本左侧,不受文本对齐方式影响。
2.2.2 核心对齐枚举值(Qt::Alignment)
和之前 QListWidgetItem、QTableWidgetItem 的对齐枚举值完全一样,我们再回顾一遍,方便查阅:
| 枚举值 | 功能说明 | |
|---|---|---|
Qt::AlignLeft |
水平左对齐(默认); | |
Qt::AlignRight |
水平右对齐; | |
Qt::AlignHCenter |
水平居中; | |
Qt::AlignCenter |
水平 + 垂直居中(等价于 `AlignHCenter | AlignVCenter`); |
Qt::AlignTop |
垂直顶部对齐; | |
Qt::AlignBottom |
垂直底部对齐; | |
Qt::AlignVCenter |
垂直居中(默认); |
2.2.3 关联 API 详解(逐词逐句,零模糊)
同样通过两个成员函数设置和获取:
1. 获取指定列的文本对齐方式:int textAlignment (int column = 0) const
函数原型:
int QTreeWidgetItem::textAlignment(int column = 0) const;
逐词逐句底层解析:
int:返回值类型,返回对齐方式的组合值(是Qt::Alignment枚举的整数组合);QTreeWidgetItem:::成员函数;textAlignment():函数名,"获取文本对齐方式" 的意思;int column = 0:入参,指定列号,默认第 0 列;const:常成员函数。
2. 设置指定列的文本对齐方式:void setTextAlignment (int column = 0, int alignment)
函数原型:
void QTreeWidgetItem::setTextAlignment(int column = 0, int alignment);
逐词逐句底层解析:
void:无返回值;QTreeWidgetItem:::成员函数;setTextAlignment():函数名,"设置文本对齐方式" 的意思;int column = 0:入参,指定列号,默认第 0 列;int alignment:入参,对齐方式的组合值,通常传入Qt::Alignment枚举的组合。
2.2.4 使用示例
#include <QTreeWidgetItem>
#include <QSize>
#include <Qt>
// 假设 ui->treeWidget 已经存在
// 示例:设置第 0 列文本水平+垂直居中
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0, "居中节点");
item->setTextAlignment(0, Qt::AlignCenter); // 水平+垂直居中
item->setSizeHint(0, QSize(150, 40)); // 【可选】扩大节点尺寸,对齐效果更明显
ui->treeWidget->addTopLevelItem(item);
// 示例:设置文本右对齐+垂直底部对齐
QTreeWidgetItem* item2 = new QTreeWidgetItem();
item2->setText(0, "右底对齐");
item2->setTextAlignment(0, Qt::AlignRight | Qt::AlignBottom);
ui->treeWidget->addTopLevelItem(item2);
2.3 属性三:icon------ 树形节点持有的图标(按列设置)
2.3.1 属性的核心定义
icon 是 QTreeWidgetItem 用于增强节点视觉辨识度的核心属性 ------ 它为指定列设置展示图标,默认操作第 0 列;图标显示在文本左侧,未设置时无图标。
通俗理解:icon 就像 "给这个节点贴个小图标"------ 比如文件夹贴个文件夹图标,文件贴个文件图标,图片贴个图片图标;这样用户一眼就能看出这个节点是什么类型。
这里有几个超级重要的规则,必须牢记,刻在脑子里:
- 尺寸控制!(超级重要!说三遍!) :
- 图标显示尺寸由 QTreeWidget::setIconSize() 全局控制!
- 单个节点无法单独设置图标的显示尺寸!
- 所有节点的图标显示尺寸都是一样的!
- 资源路径 :使用资源文件时路径需以
:/开头,本地图片需传入完整路径; - 状态适配 :QIcon 自动适配节点选中 / 未选中状态,也可通过
addPixmap()自定义状态图标。
2.3.2 关联 API 详解(逐词逐句,零模糊)
通过两个成员函数设置和获取:
1. 获取指定列的图标:QIcon icon (int column = 0) const
函数原型:
QIcon QTreeWidgetItem::icon(int column = 0) const;
逐词逐句底层解析:
QIcon:返回值类型,返回图标对象;QTreeWidgetItem:::成员函数;icon():函数名,"获取图标" 的意思;int column = 0:入参,指定列号,默认第 0 列;const:常成员函数。
2. 设置指定列的图标:void setIcon (int column = 0, const QIcon& icon)
函数原型:
void QTreeWidgetItem::setIcon(int column = 0, const QIcon& icon);
逐词逐句底层解析:
void:无返回值;QTreeWidgetItem:::成员函数;setIcon():函数名,"设置图标" 的意思;int column = 0:入参,指定列号,默认第 0 列;const QIcon& icon:入参,要设置的图标对象,常量引用避免拷贝。
2.3.3 使用示例
#include <QTreeWidgetItem>
#include <QTreeWidget>
#include <QIcon>
#include <QSize>
#include <QApplication>
#include <QStyle>
// 【必须!】第一步:先设置 QTreeWidget 的全局图标尺寸(所有节点共用!)
ui->treeWidget->setIconSize(QSize(20, 20)); // 图标显示为 20x20 像素
// 假设 ui->treeWidget 已经存在
// 示例1:为第 0 列设置资源文件图标
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0, "带图标节点");
item->setIcon(0, QIcon(":/images/folder.png")); // 资源文件路径以 :/ 开头
ui->treeWidget->addTopLevelItem(item);
// 示例2:使用系统图标(比如文件夹图标、文件图标)
QTreeWidgetItem* item2 = new QTreeWidgetItem();
item2->setText(0, "系统图标节点");
QIcon systemIcon = QApplication::style()->standardIcon(QStyle::SP_DirIcon); // 系统文件夹图标
item2->setIcon(0, systemIcon);
ui->treeWidget->addTopLevelItem(item2);
2.4 属性四:font------ 树形节点文本的字体样式(按列设置)
2.4.1 属性的核心定义
font 是 QTreeWidgetItem 用于自定义指定列文本字体样式的属性 ------ 它支持设置字体大小、粗细、字体家族等,默认操作第 0 列;未设置时继承父节点或 QTreeWidget 的字体样式。
通俗理解:font 就像 "给节点的文字换个字体"------ 比如换成微软雅黑、换成黑体、调大字号、加粗显示;让重要的节点看起来更显眼。
这里有几个超级重要的规则,必须牢记:
- 颜色独立!(超级重要!说三遍!) :
- QFont 仅控制字体样式(大小、粗细、字体家族)!
- 文本颜色不包含在 QFont 里!
- 文本颜色需通过
setForeground(int column, const QBrush&)单独设置!
- 优先级:节点字体 > 父节点字体 > QTreeWidget 全局字体 > 应用程序默认字体;
- 动态生效:设置后立即刷新节点显示,无需额外刷新树形控件。
2.4.2 关联 API 详解(逐词逐句,零模糊)
通过两个成员函数设置和获取:
1. 获取指定列的字体:QFont font (int column = 0) const
函数原型:
QFont QTreeWidgetItem::font(int column = 0) const;
逐词逐句底层解析:
QFont:返回值类型,返回字体对象;QTreeWidgetItem:::成员函数;font():函数名,"获取字体" 的意思;int column = 0:入参,指定列号,默认第 0 列;const:常成员函数。
2. 设置指定列的字体:void setFont (int column = 0, const QFont& font)
函数原型:
void QTreeWidgetItem::setFont(int column = 0, const QFont& font);
逐词逐句底层解析:
void:无返回值;QTreeWidgetItem:::成员函数;setFont():函数名,"设置字体" 的意思;int column = 0:入参,指定列号,默认第 0 列;const QFont& font:入参,要设置的字体对象,常量引用避免拷贝。
2.4.3 使用示例
#include <QTreeWidgetItem>
#include <QFont>
#include <QGuiApplication> // Qt::blue 等颜色定义
// 假设 ui->treeWidget 已经存在
// 示例:设置第 0 列文本为微软雅黑、12 号、粗体
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0, "自定义字体节点");
// 设置字体
QFont font("Microsoft YaHei", 12, QFont::Bold);
item->setFont(0, font);
// 【额外!】设置文本颜色(QFont 不包含颜色,需单独设置!)
item->setForeground(0, Qt::blue);
ui->treeWidget->addTopLevelItem(item);
2.5 属性五:hidden------ 树形节点是否隐藏的状态属性
2.5.1 属性的核心定义
hidden 是 QTreeWidgetItem 用于控制节点是否在树形控件中显示 的状态属性 ------ 默认值为 false(显示);隐藏的节点不占用布局空间,也无法被交互(点击 / 选中 / 展开)。
通俗理解:hidden 就像 "把这个节点藏起来"------ 藏起来后,用户在界面上看不到它,也点不到它;它的位置会被下面的节点自动补上。
这里有几个超级重要的规则,必须牢记:
- 布局影响:隐藏后节点从树形控件布局中移除,下方节点自动上移;
- 子节点联动!(超级重要!) :
- 隐藏父节点时,其所有子节点也会被隐藏!
- 哪怕子节点单独设置为显示(
setHidden(false)),只要父节点隐藏,子节点也看不到!
- 交互禁用:隐藏的节点无法被点击、选中、悬浮,也不会触发任何交互信号。
2.5.2 关联 API 详解(逐词逐句,零模糊)
通过两个成员函数设置和获取:
1. 判断节点是否隐藏:bool isHidden () const
函数原型:
bool QTreeWidgetItem::isHidden() const;
逐词逐句底层解析:
bool:返回值类型,true表示隐藏,false表示显示;QTreeWidgetItem:::成员函数;isHidden():函数名,"是否隐藏" 的意思;const:常成员函数。
2. 设置节点是否隐藏:void setHidden (bool hidden)
函数原型:
void QTreeWidgetItem::setHidden(bool hidden);
逐词逐句底层解析:
void:无返回值;QTreeWidgetItem:::成员函数;setHidden():函数名,"设置是否隐藏" 的意思;bool hidden:入参,true表示隐藏,false表示显示。
2.5.3 使用示例
#include <QTreeWidgetItem>
#include <QTreeWidget>
// 假设 ui->treeWidget 已经存在,并且有顶层节点
// 示例:隐藏第一个顶层节点
QTreeWidgetItem* targetItem = ui->treeWidget->topLevelItem(0);
if (targetItem != nullptr) {
targetItem->setHidden(true); // 隐藏节点
qDebug() << "节点是否隐藏:" << targetItem->isHidden(); // 输出:true
}
// 示例:显示节点
// targetItem->setHidden(false);
2.6 属性六:disabled------ 树形节点是否禁用的状态属性
2.6.1 属性的核心定义
disabled 是 QTreeWidgetItem 用于控制节点是否可交互 的状态属性 ------ 默认值为 false(启用);禁用的节点视觉上变灰,无法被点击、选中、展开 / 折叠。
通俗理解:disabled 就像 "把这个节点变成灰色,不让用户碰"------ 用户能看到它,但点不了它,选不了它,也展开 / 折叠不了它;就像 "灰色的按钮" 一样。
这里有几个超级重要的规则,必须牢记:
- 视觉表现:禁用节点文本 / 图标会变灰,区分于正常节点;
- 交互限制:禁用节点无法被点击、选中、展开 / 折叠,也不会触发交互信号;
- 子节点独立!(超级重要!和 hidden 不一样!) :
- 禁用父节点不影响子节点的启用状态!
- 子节点可以单独设置为启用或禁用,和父节点无关!
2.6.2 关联 API 详解(逐词逐句,零模糊)
通过两个成员函数设置和获取:
1. 判断节点是否禁用:bool isDisabled () const
函数原型:
bool QTreeWidgetItem::isDisabled() const;
逐词逐句底层解析:
bool:返回值类型,true表示禁用,false表示启用;QTreeWidgetItem:::成员函数;isDisabled():函数名,"是否禁用" 的意思;const:常成员函数。
2. 设置节点是否禁用:void setDisabled (bool disabled)
函数原型:
void QTreeWidgetItem::setDisabled(bool disabled);
逐词逐句底层解析:
void:无返回值;QTreeWidgetItem:::成员函数;setDisabled():函数名,"设置是否禁用" 的意思;bool disabled:入参,true表示禁用,false表示启用。
2.6.3 使用示例
#include <QTreeWidgetItem>
#include <QTreeWidget>
// 假设 ui->treeWidget 已经存在
// 示例:创建一个禁用节点
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0, "禁用节点(灰色,不可交互)");
item->setDisabled(true); // 禁用节点
ui->treeWidget->addTopLevelItem(item);
qDebug() << "节点是否禁用:" << item->isDisabled(); // 输出:true
2.7 属性七:expand(expanded)------ 树形节点是否展开的状态属性
2.7.1 属性的核心定义
首先纠正一个小笔误:你提供的资料里写的属性名是 expand,这是一个简写;Qt 官方的属性名是 expanded ,对应的方法是 isExpanded() 和 setExpanded()。
expanded 是 QTreeWidgetItem 用于控制包含子节点的节点是否展开显示子项 的状态属性 ------ 默认值为 false(折叠);展开时子节点可见,折叠时子节点隐藏。
通俗理解:expanded 就像 "打开或合上文件夹"------ 打开(展开)后,能看到文件夹里的子文件 / 子文件夹;合上(折叠)后,子文件 / 子文件夹就藏起来了;只有包含子节点的节点,展开 / 折叠才有意义。
这里有几个超级重要的规则,必须牢记:
- 无意义场景:没有子节点的节点(叶子节点),展开 / 折叠状态无视觉变化 ------ 因为它没有子节点可以显示或隐藏;
- 交互触发:用户点击节点前面的展开 / 折叠图标(小三角形),也会修改该状态;
- 信号联动 :状态变更会触发
QTreeWidget::itemExpanded()(展开时)或QTreeWidget::itemCollapsed()(折叠时)信号。
2.7.2 关联 API 详解(逐词逐句,零模糊)
通过两个成员函数设置和获取:
1. 判断节点是否展开:bool isExpanded () const
函数原型:
bool QTreeWidgetItem::isExpanded() const;
逐词逐句底层解析:
bool:返回值类型,true表示展开,false表示折叠;QTreeWidgetItem:::成员函数;isExpanded():函数名,"是否展开" 的意思;const:常成员函数。
2. 设置节点是否展开:void setExpanded (bool expanded)
函数原型:
void QTreeWidgetItem::setExpanded(bool expanded);
逐词逐句底层解析:
void:无返回值;QTreeWidgetItem:::成员函数;setExpanded():函数名,"设置是否展开" 的意思;bool expanded:入参,true表示展开,false表示折叠。
2.7.3 使用示例
#include <QTreeWidgetItem>
#include <QTreeWidget>
// 假设 ui->treeWidget 已经存在
// 示例:创建父节点并添加子节点,然后展开父节点
QTreeWidgetItem* parentItem = new QTreeWidgetItem();
parentItem->setText(0, "父节点(点击三角形展开/折叠)");
// 添加子节点
QTreeWidgetItem* childItem = new QTreeWidgetItem();
childItem->setText(0, "子节点");
parentItem->addChild(childItem); // 后面会讲 addChild 方法
// 添加到树形控件
ui->treeWidget->addTopLevelItem(parentItem);
// 【关键!】展开父节点,显示子节点
parentItem->setExpanded(true);
qDebug() << "节点是否展开:" << parentItem->isExpanded(); // 输出:true
2.8 属性八:sizeHint------ 树形节点的尺寸提示(按列设置)
2.8.1 属性的核心定义
sizeHint 是 QTreeWidgetItem 用于为指定列设置节点首选尺寸的属性 ------ 默认操作第 0 列;未设置时,节点尺寸由内容(文本 + 图标)自动计算。
通俗理解:sizeHint 就像 "给这个节点指定一个大小"------ 比如宽一点、高一点;这样节点里的文字就不会显得太挤,对齐效果也会更明显。
这里有几个超级重要的规则,必须牢记:
- 尺寸约束:设置的尺寸为 "提示值",不是 "强制值"------ 如果树形控件宽度不足,节点宽度会被压缩;
- 按列设置:不同列可设置不同尺寸,适配多列树形结构的差异化展示;
- 最小尺寸:设置的尺寸小于内容最小显示尺寸时,自动适配为内容最小尺寸 ------ 比如你设置宽度为 10px,但文字本身需要 50px 才能显示,那么节点宽度还是 50px。
2.8.2 关联 API 详解(逐词逐句,零模糊)
通过两个成员函数设置和获取:
1. 获取指定列的尺寸提示:QSize sizeHint (int column = 0) const
函数原型:
QSize QTreeWidgetItem::sizeHint(int column = 0) const;
逐词逐句底层解析:
QSize:返回值类型,返回尺寸对象(包含宽度 width 和高度 height);QTreeWidgetItem:::成员函数;sizeHint():函数名,"获取尺寸提示" 的意思;int column = 0:入参,指定列号,默认第 0 列;const:常成员函数。
2. 设置指定列的尺寸提示:void setSizeHint (int column = 0, const QSize& size)
函数原型:
void QTreeWidgetItem::setSizeHint(int column = 0, const QSize& size);
逐词逐句底层解析:
void:无返回值;QTreeWidgetItem:::成员函数;setSizeHint():函数名,"设置尺寸提示" 的意思;- 注意!你提供的资料里写的是
setSizeHints(复数),这是笔误!Qt 官方的正确方法名是setSizeHint(单数)! int column = 0:入参,指定列号,默认第 0 列;const QSize& size:入参,要设置的尺寸对象,包含宽度和高度,单位是像素。
2.8.3 使用示例
#include <QTreeWidgetItem>
#include <QSize>
// 假设 ui->treeWidget 已经存在
// 示例:设置第 0 列节点尺寸为宽 150px,高 40px
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0, "自定义尺寸节点");
item->setSizeHint(0, QSize(150, 40)); // 宽 150px,高 40px
ui->treeWidget->addTopLevelItem(item);
2.9 属性九:selected------ 树形节点是否被选中的状态属性
2.9.1 属性的核心定义
selected 是 QTreeWidgetItem 用于控制节点选中状态 的属性 ------ 默认值为 false(未选中);选中的节点会按系统 / 自定义样式高亮显示,受 QTreeWidget 选择模式影响。
通俗理解:selected 就像 "把这个节点标亮"------ 标亮后,用户能一眼看到哪个节点被选中了;你可以通过代码设置选中,也可以让用户点击选中。
这里有几个超级重要的规则,必须牢记:
- 选择模式 :受
QTreeWidget::setSelectionMode()影响 ------ 如果设为NoSelection(无选择),设置选中无效; - 信号触发 :设置选中状态会触发
QTreeWidget::itemSelectionChanged()信号; - 视觉样式 :选中高亮样式可通过 QSS 自定义(如
QTreeWidget::item:selected); - 多选适配:开启多选模式时,可同时选中多个节点。
2.9.2 关联 API 详解(逐词逐句,零模糊)
通过两个成员函数设置和获取:
1. 判断节点是否被选中:bool isSelected () const
函数原型:
bool QTreeWidgetItem::isSelected() const;
逐词逐句底层解析:
bool:返回值类型,true表示选中,false表示未选中;QTreeWidgetItem:::成员函数;isSelected():函数名,"是否被选中" 的意思;const:常成员函数。
2. 设置节点是否被选中:void setSelected (bool selected)
函数原型:
void QTreeWidgetItem::setSelected(bool selected);
逐词逐句底层解析:
void:无返回值;QTreeWidgetItem:::成员函数;setSelected():函数名,"设置是否选中" 的意思;bool selected:入参,true表示选中,false表示未选中。
2.9.3 使用示例
#include <QTreeWidgetItem>
#include <QTreeWidget>
#include <QAbstractItemView>
// 假设 ui->treeWidget 已经存在,并且有顶层节点
// 示例:设置第一个顶层节点为选中状态
QTreeWidgetItem* item = ui->treeWidget->topLevelItem(0);
if (item != nullptr) {
// 【可选】先设置树形控件为单选模式(默认通常是单选)
ui->treeWidget->setSelectionMode(QAbstractItemView::SingleSelection);
// 设置选中
item->setSelected(true);
qDebug() << "节点是否选中:" << item->isSelected(); // 输出:true
}
示例代码:
cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//OK,那么接下来我们学习多元素控件的最后一个控件的,QTreeWidget控件
//这个控件算是最高级的了,因为它本质其实就是棵树啦~~~
//我们平时没少见到说按一下某个条目的三角形,然后这个条目下面就会展示出一堆新的条目出来
//那么其实这个就是QTreeWidget控件啦
//一样,这个控件也是由一个个条目,或者说是节点组合的
//那么也就是QTreeWidgetItem
//那么本文件,我们就先来学习一下QTreeWidgetItem的属性吧
/**
* @class QTreeWidgetItem
* @brief Qt中QTreeWidget树形控件的节点条目类,表征树形结构中的单个节点
* @details QTreeWidgetItem是树形控件的最小组成单元,支持多列文本/图标展示,核心属性覆盖文本样式、显示状态、交互状态、尺寸定制等维度;
* 所有与列相关的属性(text/icon/font等)默认针对第0列,支持多列树形结构的精细化配置。
*
* 【核心特征】
* 1. 内容展示:支持多列文本、图标、字体、对齐方式的个性化配置;
* 2. 状态控制:支持隐藏/禁用/选中/展开折叠等交互状态管理;
* 3. 尺寸定制:支持按列设置节点尺寸,适配不同展示需求。
*/
// ============================== 核心属性详解 ==============================
/**
* @property QTreeWidgetItem::text
* @brief 树形节点持有的文本内容(按列存储)
* @details 核心展示属性,支持为节点的每一列设置独立文本,默认操作第0列;未设置时文本为空字符串,是树形节点最基础的展示内容。
*
* 【关联API详解】
* 1. QString text(int column = 0) const → 获取指定列的文本(默认第0列);
* 2. void setText(int column = 0, const QString& text) → 设置指定列的文本(默认第0列)。
*
* @使用示例:
* // 创建树形节点并设置第0列文本
* QTreeWidgetItem* rootItem = new QTreeWidgetItem();
* rootItem->setText(0, "根节点");
*
* // 多列树形结构:设置第1列文本
* rootItem->setText(1, "根节点描述");
* ui->treeWidget->addTopLevelItem(rootItem);
*
* 【关键注意事项】
* 1. 列号规则:列号从0开始,默认操作第0列,多列树形需先通过QTreeWidget::setColumnCount设置列数;
* 2. 富文本支持:文本可包含基础HTML标签(<b>/<font>/<br>等),复杂标签可能无法正常渲染;
* 3. 编码适配:支持UTF-8编码,可正常显示中文、特殊字符等。
*/
/**
* @property QTreeWidgetItem::textAlignment
* @brief 树形节点文本的对齐方式(按列设置)
* @details 控制指定列文本在节点区域内的水平+垂直对齐位置,默认值为Qt::AlignLeft | Qt::AlignVCenter,默认操作第0列。
*
* 【核心对齐枚举值(Qt::Alignment)】
* | 枚举值 | 功能说明 |
* |-----------------------|--------------------------------------------------------------------------|
* | Qt::AlignLeft | 水平左对齐(默认); |
* | Qt::AlignRight | 水平右对齐; |
* | Qt::AlignHCenter | 水平居中; |
* | Qt::AlignCenter | 水平+垂直居中(等价于AlignHCenter | AlignVCenter); |
* | Qt::AlignTop | 垂直顶部对齐; |
* | Qt::AlignBottom | 垂直底部对齐; |
* | Qt::AlignVCenter | 垂直居中(默认); |
*
* 【关联API详解】
* 1. int textAlignment(int column = 0) const → 获取指定列的文本对齐方式;
* 2. void setTextAlignment(int column = 0, int alignment) → 设置指定列的文本对齐方式。
*
* @使用示例:
* // 设置第0列文本水平+垂直居中
* QTreeWidgetItem* item = new QTreeWidgetItem();
* item->setText(0, "居中节点");
* item->setTextAlignment(0, Qt::AlignCenter);
*
* 【关键注意事项】
* 1. 组合使用:可通过|组合对齐方式(如Qt::AlignHCenter | Qt::AlignBottom);
* 2. 尺寸影响:节点尺寸过小时,对齐效果不明显,需配合sizeHint调整;
* 3. 图标兼容:图标始终显示在文本左侧,不受文本对齐方式影响。
*/
/**
* @property QTreeWidgetItem::icon
* @brief 树形节点持有的图标(按列设置)
* @details 为指定列设置展示图标,默认操作第0列;图标显示在文本左侧,未设置时无图标,是增强树形节点视觉辨识度的核心属性。
*
* 【关联API详解】
* 1. QIcon icon(int column = 0) const → 获取指定列的图标;
* 2. void setIcon(int column = 0, const QIcon& icon) → 设置指定列的图标。
*
* @使用示例:
* // 为第0列设置资源文件图标
* QTreeWidgetItem* item = new QTreeWidgetItem();
* item->setText(0, "带图标节点");
* item->setIcon(0, QIcon(":/images/folder.png"));
*
* // 设置树形控件图标全局尺寸
* ui->treeWidget->setIconSize(QSize(20, 20));
*
* 【关键注意事项】
* 1. 尺寸控制:图标显示尺寸由QTreeWidget::setIconSize()全局控制,单个节点无法单独设置;
* 2. 资源路径:使用资源文件时路径需以:/开头,本地图片需传入完整路径;
* 3. 状态适配:QIcon自动适配节点选中/未选中状态,也可通过addPixmap自定义状态图标。
*/
/**
* @property QTreeWidgetItem::font
* @brief 树形节点文本的字体样式(按列设置)
* @details 为指定列文本设置独立字体(大小、粗细、字体家族等),默认操作第0列;未设置时继承父节点/QTreeWidget的字体样式。
*
* 【关联API详解】
* 1. QFont font(int column = 0) const → 获取指定列的字体;
* 2. void setFont(int column = 0, const QFont& font) → 设置指定列的字体。
*
* @使用示例:
* // 设置第0列文本为微软雅黑、12号、粗体
* QTreeWidgetItem* item = new QTreeWidgetItem();
* item->setText(0, "自定义字体节点");
* QFont font("Microsoft YaHei", 12, QFont::Bold);
* item->setFont(0, font);
* // 额外设置文本颜色(字体不包含颜色,需单独设置)
* item->setForeground(0, Qt::blue);
*
* 【关键注意事项】
* 1. 颜色独立:QFont仅控制字体样式,文本颜色需通过setForeground(int column, const QBrush&)设置;
* 2. 优先级:节点字体 > 父节点字体 > QTreeWidget全局字体;
* 3. 动态生效:设置后立即刷新节点显示,无需额外刷新树形控件。
*/
/**
* @property QTreeWidgetItem::hidden
* @brief 树形节点是否隐藏的状态属性
* @details 控制节点是否在树形控件中显示,默认值为false(显示);隐藏的节点不占用布局空间,也无法被交互(点击/选中)。
*
* 【关联API详解】
* 1. bool isHidden() const → 判断节点是否隐藏;
* 2. void setHidden(bool hidden) → 设置节点是否隐藏(true=隐藏,false=显示)。
*
* @使用示例:
* // 隐藏指定节点
* QTreeWidgetItem* targetItem = ui->treeWidget->topLevelItem(0);
* if (targetItem) {
* targetItem->setHidden(true); // 隐藏节点
* }
*
* 【关键注意事项】
* 1. 布局影响:隐藏后节点从树形控件布局中移除,下方节点自动上移;
* 2. 子节点联动:隐藏父节点时,其所有子节点也会被隐藏(即使子节点设置为显示);
* 3. 交互禁用:隐藏的节点无法被点击、选中、悬浮,也不会触发任何交互信号。
*/
/**
* @property QTreeWidgetItem::disabled
* @brief 树形节点是否禁用的状态属性
* @details 控制节点是否可交互,默认值为false(启用);禁用的节点视觉上变灰,无法被点击、选中、展开/折叠。
*
* 【关联API详解】
* 1. bool isDisabled() const → 判断节点是否禁用;
* 2. void setDisabled(bool disabled) → 设置节点是否禁用(true=禁用,false=启用)。
*
* @使用示例:
* // 禁用指定节点
* QTreeWidgetItem* item = new QTreeWidgetItem();
* item->setText(0, "禁用节点");
* item->setDisabled(true);
* ui->treeWidget->addTopLevelItem(item);
*
* 【关键注意事项】
* 1. 视觉表现:禁用节点文本/图标会变灰,区分于正常节点;
* 2. 交互限制:禁用节点无法被点击、选中、展开/折叠,也不会触发交互信号;
* 3. 子节点独立:禁用父节点不影响子节点的启用状态(子节点可单独设置)。
*/
/**
* @property QTreeWidgetItem::expand
* @brief 树形节点是否展开的状态属性(注:官方属性名为expanded,此处为简写)
* @details 控制包含子节点的树形节点是否展开显示子项,默认值为false(折叠);展开时子节点可见,折叠时子节点隐藏。
*
* 【关联API详解】
* 1. bool isExpanded() const → 判断节点是否展开;
* 2. void setExpanded(bool expanded) → 设置节点是否展开(true=展开,false=折叠)。
*
* @使用示例:
* // 创建父节点并添加子节点
* QTreeWidgetItem* parentItem = new QTreeWidgetItem();
* parentItem->setText(0, "父节点");
* QTreeWidgetItem* childItem = new QTreeWidgetItem();
* childItem->setText(0, "子节点");
* parentItem->addChild(childItem);
* ui->treeWidget->addTopLevelItem(parentItem);
*
* // 展开父节点,显示子节点
* parentItem->setExpanded(true);
*
* 【关键注意事项】
* 1. 无意义场景:无子女节点的节点,展开/折叠状态无视觉变化;
* 2. 交互触发:用户点击节点前的展开/折叠图标,也会修改该状态;
* 3. 信号联动:状态变更会触发QTreeWidget::itemExpanded()/itemCollapsed()信号。
*/
/**
* @property QTreeWidgetItem::sizeHint
* @brief 树形节点的尺寸提示(按列设置)
* @details 为指定列设置节点的首选尺寸,默认操作第0列;未设置时,节点尺寸由内容(文本+图标)自动计算。
*
* 【关联API详解】
* 1. QSize sizeHint(int column = 0) const → 获取指定列的尺寸提示;
* 2. void setSizeHint(int column = 0, const QSize& size) → 设置指定列的尺寸提示。
*
* @使用示例:
* // 设置第0列节点尺寸为宽150px,高40px
* QTreeWidgetItem* item = new QTreeWidgetItem();
* item->setText(0, "自定义尺寸节点");
* item->setSizeHint(0, QSize(150, 40));
*
* 【关键注意事项】
* 1. 尺寸约束:设置的尺寸为"提示值",树形控件宽度不足时,节点宽度会被压缩;
* 2. 按列设置:不同列可设置不同尺寸,适配多列树形结构的差异化展示;
* 3. 最小尺寸:设置的尺寸小于内容最小显示尺寸时,自动适配为内容最小尺寸。
*/
/**
* @property QTreeWidgetItem::selected
* @brief 树形节点是否被选中的状态属性
* @details 控制节点的选中状态,默认值为false(未选中);选中的节点会按系统/自定义样式高亮显示,受QTreeWidget选择模式影响。
*
* 【关联API详解】
* 1. bool isSelected() const → 判断节点是否被选中;
* 2. void setSelected(bool selected) → 设置节点是否被选中(true=选中,false=未选中)。
*
* @使用示例:
* // 设置指定节点为选中状态
* QTreeWidgetItem* item = ui->treeWidget->topLevelItem(0);
* if (item) {
* item->setSelected(true);
* }
*
* 【关键注意事项】
* 1. 选择模式:受QTreeWidget::setSelectionMode()影响,无选择权限时设置选中无效;
* 2. 信号触发:设置选中状态会触发QTreeWidget::itemSelectionChanged()信号;
* 3. 视觉样式:选中高亮样式可通过QSS自定义(如QTreeWidget::item:selected);
* 4. 多选适配:开启多选模式时,可同时选中多个节点。
*/
//可以看出,其实是和我们之前学习的差不多啦!!!
}
Widget::~Widget()
{
delete ui;
}
第三章 QTreeWidgetItem 类核心方法详解
讲完了 QTreeWidgetItem 类的核心属性,我们接下来讲 QTreeWidgetItem 的核心方法 ------ 这些方法聚焦于 "父子节点关系管理",是构建树形结构、管理节点层级的核心接口。按照你提供的顺序,我们讲:addChild、childCount、child、takeChild、removeChild、parent。
3.1 方法一:addChild ()------ 为当前节点新增子节点(追加到子节点列表末尾)
3.1.1 方法的核心定义
addChild() 是 QTreeWidgetItem 最核心、最常用 的子节点添加方法 ------ 它将传入的 child 节点设为当前节点的子节点,追加到子节点列表的末尾;child 的所有权移交至当前节点,无需手动管理内存。
通俗理解:addChild() 就像 "在当前文件夹里新建一个子文件夹或文件"------ 新建的子项会放在当前文件夹的最后面;而且,这个子项归当前文件夹管了,当前文件夹被删除时,子项也会自动被删除。
这里有几个超级重要的规则,必须牢记,刻在脑子里:
- 所有权移交!(超级重要!说三遍!) :
child节点的所有权归当前节点!- 删除当前节点时,会自动释放所有子节点的内存!
- 无需手动 delete 子节点!
- 重复添加!(超级重要!) :
- 同一
child节点不可重复添加到多个父节点! - 也不可重复添加到同一个父节点多次!
- 否则会导致未定义行为(程序崩溃、内存泄漏等)!
- 同一
- 下标顺序 :新增的子节点会追加到子节点列表的末尾,下标为
childCount()-1(子节点总数减 1)。
3.1.2 关联 API 详解(逐词逐句,零模糊)
1. 为当前节点新增子节点:void addChild (QTreeWidgetItem* child)
函数原型:
void QTreeWidgetItem::addChild(QTreeWidgetItem* child);
逐词逐句底层解析:
void:无返回值;QTreeWidgetItem:::成员函数;addChild():函数名,"添加子节点" 的意思;QTreeWidgetItem* child:入参,要添加的子节点指针;- 必须是
new出来的堆对象! - 不可为
nullptr! - 不可重复添加!
- 必须是
参数说明:
child:要添加的子节点指针,QTreeWidgetItem*类型;- 必须是堆对象(用
new创建); - 不能是栈对象(否则程序崩溃);
- 不能是
nullptr。
- 必须是堆对象(用
3.1.3 使用示例
#include <QTreeWidgetItem>
#include <QTreeWidget>
// 假设 ui->treeWidget 已经存在
// 示例:创建顶层节点,然后为其添加两个子节点
// 1. 创建顶层节点
QTreeWidgetItem* parentItem = new QTreeWidgetItem();
parentItem->setText(0, "父节点");
ui->treeWidget->addTopLevelItem(parentItem); // 后面会讲 addTopLevelItem
// 2. 为父节点添加第一个子节点
QTreeWidgetItem* childItem1 = new QTreeWidgetItem();
childItem1->setText(0, "子节点 1");
parentItem->addChild(childItem1); // 追加到子节点列表末尾,下标 0
// 3. 为父节点添加第二个子节点
QTreeWidgetItem* childItem2 = new QTreeWidgetItem();
childItem2->setText(0, "子节点 2");
parentItem->addChild(childItem2); // 追加到子节点列表末尾,下标 1
// 4. 展开父节点,显示子节点
parentItem->setExpanded(true);
3.2 方法二:childCount ()------ 获取当前节点的子节点总数
3.2.1 方法的核心定义
childCount() 是 QTreeWidgetItem 用于查询当前节点子节点数量 的核心方法 ------ 它返回当前节点下直接子节点的数量(不包含子节点的子节点,即仅一级子节点),无子女节点时返回 0。
通俗理解:childCount() 就像 "数一数当前文件夹里有多少个直接的子文件 / 子文件夹"------ 只数 "直接在这个文件夹里的",不数 "子文件夹里的子文件";如果文件夹是空的,就返回 0。
这里有几个超级重要的规则,必须牢记:
- 层级限制!(超级重要!) :
- 仅统计直接子节点!
- 不递归统计孙节点、曾孙节点等!
- 比如:父节点有一个子节点,子节点又有一个子节点 ------ 那么父节点的
childCount()是 1,不是 2!
- 实时更新 :添加 / 删除子节点(
addChild/takeChild/removeChild)后,childCount()立即更新; - 空节点计数:即使子节点无文本 / 图标(空节点),仍计入总数。
3.2.2 关联 API 详解(逐词逐句,零模糊)
1. 获取当前节点的子节点总数:int childCount () const
函数原型:
int QTreeWidgetItem::childCount() const;
逐词逐句底层解析:
int:返回值类型,返回子节点总数;QTreeWidgetItem:::成员函数;childCount():函数名,"子节点数量" 的意思;const:常成员函数。
返回值说明:
- 返回
int类型的整数; - 范围:
≥ 0; - 无直接子节点时返回 0。
3.2.3 使用示例
#include <QTreeWidgetItem>
#include <QTreeWidget>
#include <QDebug>
// 假设 ui->treeWidget 已经存在,并且有一个包含子节点的顶层节点
// 示例:遍历当前节点的所有子节点
QTreeWidgetItem* parentItem = ui->treeWidget->topLevelItem(0);
if (parentItem != nullptr) {
int childNum = parentItem->childCount();
qDebug() << "父节点子节点总数:" << childNum;
// 遍历所有直接子节点
for (int i = 0; i < childNum; ++i) {
QTreeWidgetItem* child = parentItem->child(i); // 后面会讲 child 方法
if (child != nullptr) {
qDebug() << "第" << i+1 << "个子节点文本:" << child->text(0);
}
}
}
3.3 方法三:child ()------ 按下标获取当前节点的指定子节点
3.3.1 方法的核心定义
child() 是 QTreeWidgetItem 用于精准获取指定下标子节点 的核心方法 ------ 它返回下标为 index 的直接子节点指针;index 超出有效范围时返回 nullptr。
通俗理解:child() 就像 "按位置拿当前文件夹里的子文件 / 子文件夹"------ 比如 "拿第 1 个""拿第 2 个";如果位置不对(比如只有 2 个子节点,你拿第 3 个),就拿不到(返回 nullptr)。
这里有几个超级重要的规则,必须牢记,刻在脑子里:
- 下标规则(超级重要!开篇就讲!) :
- 下标从 0 开始!
- 有效范围:
[0, childCount()-1]; - 第 1 个子节点下标是 0,第 2 个是 1,以此类推;
- 判空强制!(超级重要!说三遍!) :
- 下标无效时返回
nullptr! - 必须先判空再操作! 直接操作会导致程序崩溃!
- 下标无效时返回
- 层级限制!(超级重要!) :
- 仅返回直接子节点!
- 无法通过该方法直接获取孙节点!
- 要获取孙节点,需先获取子节点,再调用子节点的
child()方法!
3.3.2 关联 API 详解(逐词逐句,零模糊)
1. 按下标获取当前节点的指定子节点:QTreeWidgetItem* child (int index) const
函数原型:
QTreeWidgetItem* QTreeWidgetItem::child(int index) const;
逐词逐句底层解析:
QTreeWidgetItem*:返回值类型,返回子节点指针;QTreeWidgetItem:::成员函数;child():函数名,"获取子节点" 的意思;int index:入参,子节点的下标,从 0 开始;const:常成员函数。
参数说明:
index:子节点的下标,int类型,从 0 开始;- 有效范围:
0 ≤ index < childCount()。
- 有效范围:
返回值说明:
- 返回
QTreeWidgetItem*类型的指针; - 下标有效 → 返回对应子节点指针;
- 下标无效 → 返回
nullptr; - 必须先判空再操作!
3.3.3 使用示例
#include <QTreeWidgetItem>
#include <QTreeWidget>
#include <QDebug>
// 假设 ui->treeWidget 已经存在,并且有一个包含子节点的顶层节点
// 示例:获取父节点的第一个子节点(下标 0)
QTreeWidgetItem* parentItem = ui->treeWidget->topLevelItem(0);
if (parentItem != nullptr) {
QTreeWidgetItem* firstChild = parentItem->child(0);
if (firstChild != nullptr) { // 【必须!】判空!
qDebug() << "第一个子节点文本:" << firstChild->text(0);
} else {
qDebug() << "无第一个子节点";
}
}
3.4 方法四:takeChild ()------ 按下标删除当前节点的指定子节点,并返回被删除的节点指针
3.4.1 方法的核心定义
takeChild() 是 QTreeWidgetItem 用于移除并获取指定下标子节点 的核心方法 ------ 它仅将子节点从当前节点的子列表中移除(不自动释放内存 ),需手动 delete 返回的指针避免内存泄漏。
通俗理解:takeChild() 就像 "把当前文件夹里的某个子文件 / 子文件夹拿出来"------ 拿出来后,这个子项就不在当前文件夹里了;但它还在内存里,你可以把它放到别的文件夹里,或者手动把它删掉(delete);如果你不删掉它,它就会一直占内存,导致内存泄漏!
这里有几个超级重要的规则,必须牢记,刻在脑子里:
- 内存管理!(超级重要!说三遍!) :
takeChild()仅 "移除" 子节点,不自动释放内存!- 必须手动
delete返回的指针! 否则内存泄漏! - 这点和
addChild()不一样!
- 下标偏移(超级重要!) :
- 删除子节点后,后续子节点的下标自动 -1!
- 比如删除下标 1 的子节点,原下标 2 的子节点变为下标 1,原下标 3 变为下标 2,以此类推;
- 子节点状态:被移除的子节点仍包含其所有子节点,可重新添加到其他父节点或树形控件中(前提是未释放内存)。
3.4.2 关联 API 详解(逐词逐句,零模糊)
1. 按下标删除当前节点的指定子节点,并返回被删除的节点指针:QTreeWidgetItem* takeChild (int index)
函数原型:
QTreeWidgetItem* QTreeWidgetItem::takeChild(int index);
逐词逐句底层解析:
QTreeWidgetItem*:返回值类型,返回被移除的子节点指针;QTreeWidgetItem:::成员函数;takeChild():函数名,"拿走子节点" 的意思;int index:入参,要移除的子节点下标,从 0 开始。
参数说明:
index:要移除的子节点下标,int类型,从 0 开始;- 有效范围:
0 ≤ index < childCount()。
- 有效范围:
返回值说明:
- 返回
QTreeWidgetItem*类型的指针; - 下标有效 → 返回被移除的子节点指针;
- 下标无效 → 返回
nullptr; - 必须手动
delete返回的指针! 否则内存泄漏!
3.4.3 使用示例
#include <QTreeWidgetItem>
#include <QTreeWidget>
#include <QDebug>
// 假设 ui->treeWidget 已经存在,并且有一个包含至少 2 个子节点的顶层节点
// 示例:删除父节点的第二个子节点(下标 1)并释放内存
QTreeWidgetItem* parentItem = ui->treeWidget->topLevelItem(0);
if (parentItem != nullptr && parentItem->childCount() > 1) {
// 1. 移除下标 1 的子节点
QTreeWidgetItem* deletedChild = parentItem->takeChild(1);
if (deletedChild != nullptr) {
qDebug() << "删除的子节点文本:" << deletedChild->text(0);
// 2. 【必须!】手动释放内存!
delete deletedChild;
deletedChild = nullptr; // 【可选】置空,避免野指针
}
}
3.5 方法五:removeChild ()------ 按节点对象删除当前节点的指定子节点
3.5.1 方法的核心定义
removeChild() 是 QTreeWidgetItem 用于根据节点对象移除指定子节点 的精准删除方法 ------ 它根据传入的 child 对象删除对应的直接子节点,删除成功返回 true,失败返回 false(如 child 不是当前节点的子节点)。
通俗理解:removeChild() 就像 "拿着一个子文件 / 子文件夹的对象,把它从当前文件夹里删掉"------ 和 takeChild() 不一样的是,它是 "按对象删",不是 "按下标删";而且它也不自动释放内存,你还是要手动 delete。
这里有几个超级重要的规则,必须牢记:
- 内存管理!(超级重要!说三遍!) :
removeChild()仅 "移除" 子节点,需手动deletechild 指针释放内存!- 否则内存泄漏!
- 匹配规则(超级重要!) :
- 仅删除当前节点的直接子节点!
child为孙节点、其他节点的子节点、或nullptr时,返回false!
- 结果校验:需通过返回值判断删除是否成功,避免空指针操作。
3.5.2 关联 API 详解(逐词逐句,零模糊)
1. 按节点对象删除当前节点的指定子节点:bool removeChild (QTreeWidgetItem* child)
函数原型:
bool QTreeWidgetItem::removeChild(QTreeWidgetItem* child);
逐词逐句底层解析:
bool:返回值类型,true表示删除成功,false表示删除失败;QTreeWidgetItem:::成员函数;removeChild():函数名,"移除子节点" 的意思;QTreeWidgetItem* child:入参,要删除的子节点对象指针。
参数说明:
child:要删除的子节点对象指针,QTreeWidgetItem*类型;- 必须是当前节点的直接子节点;
- 不能是
nullptr。
返回值说明:
- 返回
bool类型; true:删除成功;false:删除失败(child不是当前节点的直接子节点,或child为nullptr)。
3.5.3 使用示例
#include <QTreeWidgetItem>
#include <QTreeWidget>
#include <QDebug>
// 假设 ui->treeWidget 已经存在,并且有一个包含子节点的顶层节点
// 示例:删除指定的子节点对象
QTreeWidgetItem* parentItem = ui->treeWidget->topLevelItem(0);
if (parentItem != nullptr) {
// 1. 获取第一个子节点对象
QTreeWidgetItem* targetChild = parentItem->child(0);
if (targetChild != nullptr) {
// 2. 按对象删除子节点
bool isRemoved = parentItem->removeChild(targetChild);
if (isRemoved) {
qDebug() << "子节点删除成功";
// 3. 【必须!】手动释放内存!
delete targetChild;
targetChild = nullptr;
} else {
qDebug() << "子节点删除失败(非当前节点的子节点)";
}
}
}
3.6 方法六:parent ()------ 获取当前节点的父节点
3.6.1 方法的核心定义
parent() 是 QTreeWidgetItem 用于反向查询节点层级关系 的核心方法 ------ 它返回当前节点的直接父节点 指针;当前节点为顶层节点(无父节点)时返回 nullptr。
通俗理解:parent() 就像 "问这个子文件 / 子文件夹:'你的爸爸(父文件夹)是谁?'"------ 它会告诉你父节点的指针;如果这个节点是顶层节点(没有爸爸,直接在树形控件的最上面),它就说 "没有爸爸"(返回 nullptr)。
这里有几个超级重要的规则,必须牢记:
- 层级限制!(超级重要!) :
- 仅返回直接父节点!
- 无法直接获取祖父节点(爸爸的爸爸)!
- 要获取祖父节点,需先获取父节点,再调用父节点的
parent()方法!
- 顶层节点 :通过
QTreeWidget::addTopLevelItem()添加的节点为顶层节点,parent()返回nullptr; - 动态更新 :子节点被移除(
takeChild/removeChild)后,其parent()返回nullptr。
3.6.2 关联 API 详解(逐词逐句,零模糊)
1. 获取当前节点的父节点:QTreeWidgetItem* parent () const
函数原型:
QTreeWidgetItem* QTreeWidgetItem::parent() const;
逐词逐句底层解析:
QTreeWidgetItem*:返回值类型,返回父节点指针;QTreeWidgetItem:::成员函数;parent():函数名,"获取父节点" 的意思;const:常成员函数。
返回值说明:
- 返回
QTreeWidgetItem*类型的指针; - 当前节点有父节点 → 返回直接父节点指针;
- 当前节点为顶层节点 → 返回
nullptr; - 【可选】判空后再操作。
3.6.3 使用示例
#include <QTreeWidgetItem>
#include <QTreeWidget>
#include <QDebug>
// 假设 ui->treeWidget 已经存在,并且有一个包含子节点的顶层节点
// 示例:获取子节点的父节点,并打印父节点文本
QTreeWidgetItem* parentItem = ui->treeWidget->topLevelItem(0);
if (parentItem != nullptr) {
QTreeWidgetItem* childItem = parentItem->child(0);
if (childItem != nullptr) {
QTreeWidgetItem* childsParent = childItem->parent();
if (childsParent != nullptr) {
qDebug() << "子节点的父节点文本:" << childsParent->text(0);
} else {
qDebug() << "该子节点无父节点(为顶层节点)";
}
}
}
示例代码:
cpp
#include "widget.h"
#include "ui_widget.h"
#include <QTreeWidget>
#include <QTreeWidgetItem>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//OK,那么本文件我们就来学习一下QTreeWidgetItem的核心方法
//前面说过,QTreeWidget本质上就是一棵树,所以就会有多个父节点和子节点
//所以我们可以向某个父节点添加子节点,虽然这个父节点可能是另一个节点的子节点
//那么在我们之前学习了AVL树红黑树等等树之后,对于这方面的了解,还是很多的~~~
/**
* @class QTreeWidgetItem
* @brief Qt中QTreeWidget树形控件节点的核心父子关系管理方法
* @details 以下方法聚焦QTreeWidgetItem的父子节点操作,覆盖子节点的新增、数量查询、精准获取、删除,以及父节点的反向查询,是构建树形结构、管理节点层级关系的核心接口;
* 所有子节点操作均遵循"下标从0开始"的规则,支持动态调整树形节点的层级结构。
*/
// ============================== 核心方法详解 ==============================
/**
* @fn void QTreeWidgetItem::addChild(QTreeWidgetItem* child)
* @brief 为当前节点**新增子节点**(追加到子节点列表末尾)
* @details 核心子节点添加方法,将传入的child节点设为当前节点的子节点,child的所有权移交至当前节点,无需手动管理内存。
*
* @参数说明:
* @param child - QTreeWidgetItem*类型,要添加的子节点指针(不可为nullptr)。
*
* @使用示例:
* // 创建顶层节点
* QTreeWidgetItem* parentItem = new QTreeWidgetItem();
* parentItem->setText(0, "父节点");
* ui->treeWidget->addTopLevelItem(parentItem);
*
* // 为父节点添加子节点
* QTreeWidgetItem* childItem1 = new QTreeWidgetItem();
* childItem1->setText(0, "子节点1");
* parentItem->addChild(childItem1);
*
* QTreeWidgetItem* childItem2 = new QTreeWidgetItem();
* childItem2->setText(0, "子节点2");
* parentItem->addChild(childItem2); // 追加到子节点列表末尾
*
* 【关键注意事项】
* 1. 所有权移交:child节点的所有权归当前节点,删除当前节点时会自动释放所有子节点;
* 2. 重复添加:同一child节点不可重复添加到多个父节点(会导致未定义行为);
* 3. 下标顺序:新增的子节点会追加到子节点列表末尾,下标为childCount()-1。
*/
/**
* @fn int QTreeWidgetItem::childCount() const
* @brief 获取当前节点的**子节点总数**
* @details 核心子节点查询方法,返回当前节点下直接子节点的数量(不包含子节点的子节点,即仅一级子节点),无子女节点时返回0。
*
* @返回值说明:
* @return int - 直接子节点个数(≥0)。
*
* @使用示例:
* // 遍历当前节点的所有子节点
* QTreeWidgetItem* parentItem = ui->treeWidget->topLevelItem(0);
* if (parentItem) {
* int childNum = parentItem->childCount();
* qDebug() << "父节点子节点总数:" << childNum;
* // 遍历所有子节点
* for (int i = 0; i < childNum; ++i) {
* QTreeWidgetItem* child = parentItem->child(i);
* if (child) qDebug() << "第" << i+1 << "个子节点文本:" << child->text(0);
* }
* }
*
* 【关键注意事项】
* 1. 层级限制:仅统计**直接子节点**,不递归统计孙节点、曾孙节点等;
* 2. 实时更新:添加/删除子节点(addChild/takeChild/removeChild)后,childCount()立即更新;
* 3. 空节点计数:即使子节点无文本/图标(空节点),仍计入总数。
*/
/**
* @fn QTreeWidgetItem* QTreeWidgetItem::child(int index) const
* @brief 按**下标**获取当前节点的指定子节点
* @details 精准子节点查询方法,返回下标为index的直接子节点指针;index超出有效范围时返回nullptr。
*
* @参数说明:
* @param index - int类型,子节点下标(从0开始计数)。
*
* @返回值说明:
* @return QTreeWidgetItem* - 指定下标的子节点指针(下标无效返回nullptr)。
*
* @使用示例:
* // 获取父节点的第一个子节点(下标0)
* QTreeWidgetItem* parentItem = ui->treeWidget->topLevelItem(0);
* if (parentItem) {
* QTreeWidgetItem* firstChild = parentItem->child(0);
* if (firstChild) {
* qDebug() << "第一个子节点文本:" << firstChild->text(0);
* } else {
* qDebug() << "无第一个子节点";
* }
* }
*
* 【关键注意事项】
* 1. 下标规则:下标从0开始,有效范围为[0, childCount()-1];
* 2. 判空强制:下标无效时返回nullptr,直接操作会导致程序崩溃;
* 3. 层级限制:仅返回直接子节点,无法通过该方法获取孙节点(需先获取子节点,再调用其child方法)。
*/
/**
* @fn QTreeWidgetItem* QTreeWidgetItem::takeChild(int index)
* @brief 按**下标**删除当前节点的指定子节点,并返回被删除的节点指针
* @details 核心子节点删除方法,仅将子节点从当前节点的子列表中移除(不自动释放内存),需手动delete返回的指针避免内存泄漏。
*
* @参数说明:
* @param index - int类型,要删除的子节点下标(从0开始计数)。
*
* @返回值说明:
* @return QTreeWidgetItem* - 被删除的子节点指针(下标无效返回nullptr)。
*
* @使用示例:
* // 删除父节点的第二个子节点(下标1)并释放内存
* QTreeWidgetItem* parentItem = ui->treeWidget->topLevelItem(0);
* if (parentItem && parentItem->childCount() > 1) {
* QTreeWidgetItem* deletedChild = parentItem->takeChild(1);
* if (deletedChild) {
* qDebug() << "删除的子节点文本:" << deletedChild->text(0);
* delete deletedChild; // 必须手动释放,否则内存泄漏
* deletedChild = nullptr;
* }
* }
*
* 【关键注意事项】
* 1. 内存管理:takeChild仅"移除"子节点,**必须手动delete返回指针**释放内存;
* 2. 下标偏移:删除子节点后,后续子节点下标自动-1(如删除下标1,原下标2变为下标1);
* 3. 子节点状态:被移除的子节点仍可重新添加到其他父节点(未释放的前提下)。
*/
/**
* @fn bool QTreeWidgetItem::removeChild(QTreeWidgetItem* child)
* @brief 按**节点对象**删除当前节点的指定子节点
* @details 精准子节点删除方法,根据传入的child对象删除对应的直接子节点,删除成功返回true,失败返回false(如child不是当前节点的子节点)。
*
* @参数说明:
* @param child - QTreeWidgetItem*类型,要删除的子节点对象指针。
*
* @返回值说明:
* @return bool - 删除结果(true=成功,false=失败)。
*
* @使用示例:
* // 删除指定的子节点对象
* QTreeWidgetItem* parentItem = ui->treeWidget->topLevelItem(0);
* QTreeWidgetItem* targetChild = parentItem->child(0); // 获取第一个子节点
* if (parentItem && targetChild) {
* bool isRemoved = parentItem->removeChild(targetChild);
* if (isRemoved) {
* qDebug() << "子节点删除成功";
* delete targetChild; // 手动释放内存
* targetChild = nullptr;
* } else {
* qDebug() << "子节点删除失败(非当前节点的子节点)";
* }
* }
*
* 【关键注意事项】
* 1. 内存管理:removeChild仅"移除"子节点,**需手动delete child指针**释放内存;
* 2. 匹配规则:仅删除当前节点的**直接子节点**,child为孙节点/其他节点时返回false;
* 3. 结果校验:需通过返回值判断删除是否成功,避免空指针操作。
*/
/**
* @fn QTreeWidgetItem* QTreeWidgetItem::parent() const
* @brief 获取当前节点的**父节点**
* @details 反向层级查询方法,返回当前节点的直接父节点指针;当前节点为顶层节点(无父节点)时返回nullptr。
*
* @返回值说明:
* @return QTreeWidgetItem* - 父节点指针(顶层节点返回nullptr)。
*
* @使用示例:
* // 获取子节点的父节点,并打印父节点文本
* QTreeWidgetItem* childItem = ui->treeWidget->topLevelItem(0)->child(0);
* if (childItem) {
* QTreeWidgetItem* parentItem = childItem->parent();
* if (parentItem) {
* qDebug() << "子节点的父节点文本:" << parentItem->text(0);
* } else {
* qDebug() << "该子节点无父节点(为顶层节点)";
* }
* }
*
* 【关键注意事项】
* 1. 层级限制:仅返回**直接父节点**,无法直接获取祖父节点(需先获取父节点,再调用其parent方法);
* 2. 顶层节点:通过QTreeWidget::addTopLevelItem()添加的节点为顶层节点,parent()返回nullptr;
* 3. 动态更新:子节点被移除(takeChild/removeChild)后,其parent()返回nullptr。
*/
QTreeWidget* tw=new QTreeWidget(this);
// 创建一个空节点,稍后设置文本
QTreeWidgetItem* item2 = new QTreeWidgetItem();
item2->setText(0, "我是第一列的内容");
QTreeWidgetItem* item2_1 = new QTreeWidgetItem();
item2_1->setText(0, "我是第一列的子节点");
//添加子节点进去
item2->addChild(item2_1);
// 添加到树控件
tw->addTopLevelItem(item2);
//其实还是比较简单的,重点是要掌握说,子节点是添加到父节点中,而最顶层的直接和QTreeWidget接触的父节点
//才是要调用QTreeWidget的函数,否则其他的子节点都是使用addchild函数添加到父节点中哦~~~
}
Widget::~Widget()
{
delete ui;
}
第四章 QTreeWidget 核心方法详解
讲完了 QTreeWidgetItem 类的所有内容,我们接下来讲 QTreeWidget 的核心方法 ------ 这些方法聚焦于 "顶层节点管理""选中控制""结构清理""表头配置",是构建和管理树形控件的基础接口。按照你提供的顺序,我们讲:clear、addTopLevelItem、topLevelItem、topLevelItemCount、indexOfTopLevelItem、takeTopLevelItem、currentItem、setCurrentItem、setExpanded、setHeaderLabel。
4.1 方法一:clear ()------ 清空树形控件中所有节点(包含顶层节点及所有子节点)
4.1.1 方法的核心定义
clear() 是 QTreeWidget 最彻底、最常用 的清理方法 ------ 它删除树形控件中所有顶层节点及其下属的所有子节点,释放所有 QTreeWidgetItem 的内存,清空后 topLevelItemCount() 返回 0。
通俗理解:clear() 就像 "把整棵树连根拔起,全部扔掉"------ 所有节点(顶层的、子节点的、孙节点的)都会被删除,内存都会被自动释放;清空后,树形控件就像刚创建时一样,一个节点都没有了。
这里有几个超级重要的规则,必须牢记,刻在脑子里:
- 内存释放!(超级重要!说三遍!) :
clear()会自动释放所有节点(顶层 + 子节点 + 孙节点...)的内存!- 无需手动 delete 任何节点!
- 这点和
takeTopLevelItem、takeChild不一样!
- 状态重置:清空后树形控件恢复初始状态,表头名称保持不变(不会清空表头);
- 不可逆操作 :节点删除后无法恢复,需提前备份数据(如需保留节点对象,需先通过
takeTopLevelItem移除)。
4.1.2 关联 API 详解(逐词逐句,零模糊)
1. 清空树形控件中所有节点:void clear ()
函数原型:
void QTreeWidget::clear();
逐词逐句底层解析:
void:无返回值;QTreeWidget:::成员函数;clear():函数名,"清空" 的意思。
4.1.3 使用示例
#include <QTreeWidget>
#include <QDebug>
// 假设 ui->treeWidget 已经存在,并且有节点
// 示例:清空树形控件所有节点
qDebug() << "清空前顶层节点数:" << ui->treeWidget->topLevelItemCount();
ui->treeWidget->clear();
qDebug() << "清空后顶层节点数:" << ui->treeWidget->topLevelItemCount(); // 输出:0
4.2 方法二:addTopLevelItem ()------ 为树形控件新增顶层节点(追加到顶层节点列表末尾)
4.2.1 方法的核心定义
addTopLevelItem() 是 QTreeWidget 最核心、最常用 的顶层节点添加方法 ------ 它将 item 设为树形控件的顶层节点(无父节点),追加到顶层节点列表的末尾;item 的所有权移交至树形控件,无需手动管理内存。
通俗理解:addTopLevelItem() 就像 "在树形控件的最上面添加一个根节点"------ 这个根节点没有爸爸(父节点),直接归树形控件管;添加的根节点会放在最后面;树形控件被删除时,根节点及其所有子节点都会被自动释放。
这里有几个超级重要的规则,必须牢记,刻在脑子里:
- 所有权移交!(超级重要!说三遍!) :
item的所有权归树形控件!clear()/takeTopLevelItem()会自动 / 手动释放内存!- 无需手动 delete 顶层节点(除非用 takeTopLevelItem 移除)!
- 重复添加!(超级重要!) :
- 同一
item不可重复添加为顶层节点! - 也不可同时作为其他节点的子节点!
- 否则会导致未定义行为!
- 同一
- 下标顺序 :新增的顶层节点追加到列表末尾,下标为
topLevelItemCount()-1。
4.2.2 关联 API 详解(逐词逐句,零模糊)
1. 为树形控件新增顶层节点:void addTopLevelItem (QTreeWidgetItem* item)
函数原型:
void QTreeWidget::addTopLevelItem(QTreeWidgetItem* item);
逐词逐句底层解析:
void:无返回值;QTreeWidget:::成员函数;addTopLevelItem():函数名,"添加顶层节点" 的意思;QTreeWidgetItem* item:入参,要添加的顶层节点指针;- 必须是
new出来的堆对象! - 不可为
nullptr! - 不可重复添加!
- 必须是
参数说明:
item:要添加的顶层节点指针,QTreeWidgetItem*类型;- 必须是堆对象(用
new创建); - 不能是栈对象;
- 不能是
nullptr。
- 必须是堆对象(用
4.2.3 使用示例
#include <QTreeWidgetItem>
#include <QTreeWidget>
// 假设 ui->treeWidget 已经存在
// 示例:创建并添加两个顶层节点
// 1. 创建第一个顶层节点
QTreeWidgetItem* topItem1 = new QTreeWidgetItem();
topItem1->setText(0, "顶层节点 1");
ui->treeWidget->addTopLevelItem(topItem1); // 下标 0
// 2. 创建第二个顶层节点
QTreeWidgetItem* topItem2 = new QTreeWidgetItem();
topItem2->setText(0, "顶层节点 2");
ui->treeWidget->addTopLevelItem(topItem2); // 下标 1
4.3 方法三:topLevelItem ()------ 按下标获取树形控件的指定顶层节点
4.3.1 方法的核心定义
topLevelItem() 是 QTreeWidget 用于精准获取指定下标顶层节点 的核心方法 ------ 它返回下标为 index 的顶层节点指针;index 超出有效范围时返回 nullptr。
通俗理解:topLevelItem() 就像 "按位置拿树形控件最上面的根节点"------ 比如 "拿第 1 个根节点""拿第 2 个根节点";如果位置不对,就拿不到(返回 nullptr)。
这里有几个超级重要的规则,必须牢记,刻在脑子里:
- 下标规则(超级重要!开篇就讲!) :
- 下标从 0 开始!
- 有效范围:
[0, topLevelItemCount()-1];
- 判空强制!(超级重要!说三遍!) :
- 下标无效时返回
nullptr! - 必须先判空再操作! 直接操作会导致程序崩溃!
- 下标无效时返回
- 层级限制 :仅返回顶层节点,子节点需通过节点的
child()方法获取。
4.3.2 关联 API 详解(逐词逐句,零模糊)
1. 按下标获取树形控件的指定顶层节点:QTreeWidgetItem* topLevelItem (int index) const
函数原型:
QTreeWidgetItem* QTreeWidget::topLevelItem(int index) const;
逐词逐句底层解析:
QTreeWidgetItem*:返回值类型,返回顶层节点指针;QTreeWidget:::成员函数;topLevelItem():函数名,"获取顶层节点" 的意思;int index:入参,顶层节点的下标,从 0 开始;const:常成员函数。
参数说明:
index:顶层节点的下标,int类型,从 0 开始;- 有效范围:
0 ≤ index < topLevelItemCount()。
- 有效范围:
返回值说明:
- 返回
QTreeWidgetItem*类型的指针; - 下标有效 → 返回对应顶层节点指针;
- 下标无效 → 返回
nullptr; - 必须先判空再操作!
4.3.3 使用示例
#include <QTreeWidgetItem>
#include <QTreeWidget>
#include <QDebug>
// 假设 ui->treeWidget 已经存在,并且有顶层节点
// 示例:获取第一个顶层节点(下标 0)
QTreeWidgetItem* firstTopItem = ui->treeWidget->topLevelItem(0);
if (firstTopItem != nullptr) { // 【必须!】判空!
qDebug() << "第一个顶层节点文本:" << firstTopItem->text(0);
} else {
qDebug() << "无第一个顶层节点";
}
4.4 方法四:topLevelItemCount ()------ 获取树形控件的顶层节点总数
4.4.1 方法的核心定义
topLevelItemCount() 是 QTreeWidget 用于查询树形控件顶层节点数量的核心方法 ------ 它返回树形控件中顶层节点的数量(不包含顶层节点的子节点),无顶层节点时返回 0。
通俗理解:topLevelItemCount() 就像 "数一数树形控件最上面有多少个根节点"------ 只数 "直接在树形控件最上面的",不数根节点下面的子节点;如果没有根节点,就返回 0。
这里有几个超级重要的规则,必须牢记:
- 层级限制 :仅统计顶层节点,子节点数量需通过节点的
childCount()获取; - 实时更新 :添加 / 删除顶层节点(
addTopLevelItem/takeTopLevelItem/clear)后立即更新; - 空节点计数:即使顶层节点无文本 / 子节点,仍计入总数。
4.4.2 关联 API 详解(逐词逐句,零模糊)
1. 获取树形控件的顶层节点总数:int topLevelItemCount () const
函数原型:
int QTreeWidget::topLevelItemCount() const;
逐词逐句底层解析:
int:返回值类型,返回顶层节点总数;QTreeWidget:::成员函数;topLevelItemCount():函数名,"顶层节点数量" 的意思;const:常成员函数。
返回值说明:
- 返回
int类型的整数; - 范围:
≥ 0; - 无顶层节点时返回 0。
4.4.3 使用示例
#include <QTreeWidgetItem>
#include <QTreeWidget>
#include <QDebug>
// 假设 ui->treeWidget 已经存在
// 示例:遍历所有顶层节点
int topCount = ui->treeWidget->topLevelItemCount();
qDebug() << "顶层节点总数:" << topCount;
for (int i = 0; i < topCount; ++i) {
QTreeWidgetItem* topItem = ui->treeWidget->topLevelItem(i);
if (topItem != nullptr) {
qDebug() << "第" << i+1 << "个顶层节点:" << topItem->text(0);
}
}
4.5 方法五:indexOfTopLevelItem ()------ 查询指定节点在顶层节点列表中的下标
4.5.1 方法的核心定义
indexOfTopLevelItem() 是 QTreeWidget 用于反向查询顶层节点下标 的方法 ------ 它返回 item 作为顶层节点的下标;item 不是顶层节点、为 nullptr 时返回 -1。
通俗理解:indexOfTopLevelItem() 就像 "拿着一个根节点问树形控件:'这个根节点在你这里的第几个位置呀?'"------ 它会告诉你下标;如果这个节点不是根节点,或者是 nullptr,它就说 "不知道"(返回 -1)。
这里有几个超级重要的规则,必须牢记:
- 匹配规则(超级重要!) :
- 仅匹配直接顶层节点!
- 子节点、其他树形控件的节点、
nullptr均返回 -1!
- 时效性 :节点被移除(
takeTopLevelItem)后,查询其下标返回 -1; - 空指针 :传入
nullptr时返回 -1,无需额外判空。
4.5.2 关联 API 详解(逐词逐句,零模糊)
1. 查询指定节点在顶层节点列表中的下标:int indexOfTopLevelItem (QTreeWidgetItem* item) const
函数原型:
int QTreeWidget::indexOfTopLevelItem(QTreeWidgetItem* item) const;
逐词逐句底层解析:
int:返回值类型,返回顶层节点下标;QTreeWidget:::成员函数;indexOfTopLevelItem():函数名,"查询顶层节点下标" 的意思;QTreeWidgetItem* item:入参,要查询的节点指针。
参数说明:
item:要查询的节点指针,QTreeWidgetItem*类型;- 可以是
nullptr。
- 可以是
返回值说明:
- 返回
int类型的整数; item是顶层节点 → 返回对应的下标(从 0 开始);item不是顶层节点、或为nullptr→ 返回 -1。
4.5.3 使用示例
#include <QTreeWidgetItem>
#include <QTreeWidget>
#include <QDebug>
// 假设 ui->treeWidget 已经存在
// 示例:创建并添加顶层节点,查询其下标
QTreeWidgetItem* topItem = new QTreeWidgetItem();
topItem->setText(0, "测试顶层节点");
ui->treeWidget->addTopLevelItem(topItem);
int index = ui->treeWidget->indexOfTopLevelItem(topItem);
if (index != -1) {
qDebug() << "节点下标:" << index;
} else {
qDebug() << "该节点不是顶层节点";
}
4.6 方法六:takeTopLevelItem ()------ 按下标删除树形控件的指定顶层节点,并返回被删除的节点指针
4.6.1 方法的核心定义
takeTopLevelItem() 是 QTreeWidget 用于移除并获取指定下标顶层节点 的核心方法 ------ 它仅将节点从顶层列表中移除(不自动释放内存 ),需手动 delete 返回的指针避免内存泄漏。
通俗理解:takeTopLevelItem() 就像 "把树形控件最上面的某个根节点拿出来"------ 拿出来后,这个根节点就不在树形控件里了;但它还在内存里,你可以把它的子节点一起带走,放到别的地方,或者手动删掉它;如果你不删掉它,它就会一直占内存!
这里有几个超级重要的规则,必须牢记,刻在脑子里:
- 内存管理!(超级重要!说三遍!) :
takeTopLevelItem()仅 "移除" 节点,需手动delete返回指针!- 否则内存泄漏!
- 这点和
clear()不一样!
- 下标偏移(超级重要!) :
- 删除后后续顶层节点下标自动 -1!
- 比如删除下标 1 的顶层节点,原下标 2 变为下标 1,以此类推;
- 子节点联动(超级重要!) :
- 被移除的顶层节点仍包含其所有子节点!
- 可重新添加到树形控件或其他节点下(未释放的前提下)!
4.6.2 关联 API 详解(逐词逐句,零模糊)
1. 按下标删除树形控件的指定顶层节点,并返回被删除的节点指针:QTreeWidgetItem* takeTopLevelItem (int index)
函数原型:
QTreeWidgetItem* QTreeWidget::takeTopLevelItem(int index);
逐词逐句底层解析:
QTreeWidgetItem*:返回值类型,返回被移除的顶层节点指针;QTreeWidget:::成员函数;takeTopLevelItem():函数名,"拿走顶层节点" 的意思;int index:入参,要移除的顶层节点下标,从 0 开始。
参数说明:
index:要移除的顶层节点下标,int类型,从 0 开始;- 有效范围:
0 ≤ index < topLevelItemCount()。
- 有效范围:
返回值说明:
- 返回
QTreeWidgetItem*类型的指针; - 下标有效 → 返回被移除的顶层节点指针(包含其所有子节点);
- 下标无效 → 返回
nullptr; - 必须手动
delete返回的指针! 否则内存泄漏!
4.6.3 使用示例
#include <QTreeWidgetItem>
#include <QTreeWidget>
#include <QDebug>
// 假设 ui->treeWidget 已经存在,并且有至少 1 个顶层节点
// 示例:删除第一个顶层节点并释放内存
QTreeWidgetItem* deletedItem = ui->treeWidget->takeTopLevelItem(0);
if (deletedItem != nullptr) {
qDebug() << "删除的顶层节点:" << deletedItem->text(0);
// 【必须!】手动释放内存!(会自动释放其所有子节点)
delete deletedItem;
deletedItem = nullptr;
}
4.7 方法七:currentItem ()------ 获取树形控件中当前选中的节点
4.7.1 方法的核心定义
currentItem() 是 QTreeWidget 用于查询当前选中节点 的核心方法 ------ 它返回当前激活选中的节点指针(可为顶层节点或任意层级的子节点);无选中节点时返回 nullptr。
通俗理解:currentItem() 就像 "拿到树形控件上当前被标亮的那个节点"------ 不管这个节点是顶层的还是子节点,只要被标亮了,就能拿到;如果没有任何节点被标亮,就拿不到(返回 nullptr)。
这里有几个超级重要的规则,必须牢记,刻在脑子里:
- 判空必须!(超级重要!说三遍!) :
- 无选中节点时返回
nullptr! - 必须先判空再操作! 直接操作会导致程序崩溃!
- 无选中节点时返回
- 选中范围:可返回顶层节点或任意层级的子节点,不限于顶层;
- 选择模式 :受
setSelectionMode()影响,无选择权限时始终返回nullptr。
4.7.2 关联 API 详解(逐词逐句,零模糊)
1. 获取树形控件中当前选中的节点:QTreeWidgetItem* currentItem () const
函数原型:
QTreeWidgetItem* QTreeWidget::currentItem() const;
逐词逐句底层解析:
QTreeWidgetItem*:返回值类型,返回当前选中节点指针;QTreeWidget:::成员函数;currentItem():函数名,"获取当前选中节点" 的意思;const:常成员函数。
返回值说明:
- 返回
QTreeWidgetItem*类型的指针; - 有选中节点 → 返回当前选中节点指针;
- 无选中节点 → 返回
nullptr; - 必须先判空再操作!
4.7.3 使用示例
#include <QTreeWidgetItem>
#include <QTreeWidget>
#include <QDebug>
// 假设 ui->treeWidget 已经存在
// 示例:获取当前选中节点并打印其文本,以及父节点文本(如果有)
QTreeWidgetItem* selItem = ui->treeWidget->currentItem();
if (selItem != nullptr) { // 【必须!】判空!
qDebug() << "当前选中节点:" << selItem->text(0);
// 额外获取选中节点的父节点
QTreeWidgetItem* parentItem = selItem->parent();
if (parentItem != nullptr) {
qDebug() << "选中节点的父节点:" << parentItem->text(0);
} else {
qDebug() << "选中节点为顶层节点";
}
} else {
qDebug() << "无选中节点";
}
4.8 方法八:setCurrentItem ()------ 将树形控件中指定节点设为当前选中节点
4.8.1 方法的核心定义
setCurrentItem() 是 QTreeWidget 用于控制节点选中状态 的核心方法 ------ 它选中指定的节点(可为顶层或子节点);item 为 nullptr 时取消所有选中。
通俗理解:setCurrentItem() 就像 "用代码把某个节点标亮"------ 你告诉它要标亮哪个节点,它就把那个节点标亮;如果你传 nullptr,它就把所有标亮都取消。
这里有几个超级重要的规则,必须牢记:
- 有效性校验 :
item需是当前树形控件的节点(顶层 / 子节点),否则设置无效; - 信号触发 :设置后会触发
itemSelectionChanged()信号和currentItemChanged()信号; - 视觉反馈:选中的节点会按系统 / QSS 样式高亮显示。
4.8.2 关联 API 详解(逐词逐句,零模糊)
1. 将树形控件中指定节点设为当前选中节点:void setCurrentItem (QTreeWidgetItem* item)
函数原型:
void QTreeWidget::setCurrentItem(QTreeWidgetItem* item);
逐词逐句底层解析:
void:无返回值;QTreeWidget:::成员函数;setCurrentItem():函数名,"设置当前选中节点" 的意思;QTreeWidgetItem* item:入参,要选中的节点指针;- 传
nullptr则取消所有选中。
- 传
参数说明:
item:要选中的节点指针,QTreeWidgetItem*类型;- 必须是当前树形控件的节点(顶层或子节点);
- 传
nullptr取消所有选中。
4.8.3 使用示例
#include <QTreeWidgetItem>
#include <QTreeWidget>
// 假设 ui->treeWidget 已经存在,并且有顶层节点
// 示例:选中第一个顶层节点
QTreeWidgetItem* targetItem = ui->treeWidget->topLevelItem(0);
if (targetItem != nullptr) {
ui->treeWidget->setCurrentItem(targetItem);
}
// 示例:取消所有选中
// ui->treeWidget->setCurrentItem(nullptr);
4.9 方法九:setExpanded ()------ 展开 / 折叠指定节点
4.9.1 方法的核心定义
首先说明一下:你提供的资料里写的 QTreeWidget::setExpanded(bool) 是一个简化表述;Qt 官方中,QTreeWidget 确实有一个 setExpanded(const QModelIndex &index, bool expand) 方法,但这个方法需要先通过 indexFromItem() 获取节点的索引,比较麻烦。
更推荐、更直观、更常用的方法是直接使用 QTreeWidgetItem::setExpanded(bool) ------ 我们在第二章讲 expanded 属性时已经详细讲过了,这里再简单回顾一下,并补充 QTreeWidget 方法的用法。
通俗理解:不管用哪种方法,都是 "打开或合上文件夹"------ 推荐直接用节点的方法,更简单,不用转索引。
4.9.2 使用示例(推荐:节点直接调用)
#include <QTreeWidgetItem>
#include <QTreeWidget>
// 假设 ui->treeWidget 已经存在,并且有包含子节点的顶层节点
// 【推荐!】直接用节点的 setExpanded 方法
QTreeWidgetItem* topItem = ui->treeWidget->topLevelItem(0);
if (topItem != nullptr) {
topItem->setExpanded(true); // 展开节点(显示子节点)
// topItem->setExpanded(false); // 折叠节点(隐藏子节点)
}
// 【补充】QTreeWidget 控件的 setExpanded 方法(需转索引,不推荐)
// if (topItem != nullptr) {
// QModelIndex index = ui->treeWidget->indexFromItem(topItem);
// ui->treeWidget->setExpanded(index, true);
// }
4.10 方法十:setHeaderLabel ()------ 设置树形控件单列表头的显示名称
4.10.1 方法的核心定义
setHeaderLabel() 是 QTreeWidget 用于配置单列树形控件表头 的方法 ------ 它适用于单列树形控件(columnCount() = 1),设置表头(列标题)的文本;多列树形控件需使用 setHeaderLabels(const QStringList&)。
通俗理解:setHeaderLabel() 就像 "给树形控件的最上面起个标题"------ 比如文件管理器的表头叫 "名称";这个标题显示在控件的顶部。
这里有几个超级重要的规则,必须牢记:
- 列数适配 :仅适用于单列 树形控件(
columnCount() = 1),多列需用setHeaderLabels; - 视觉控制 :表头显示在控件顶部,可通过
setHeaderHidden(true)隐藏; - 动态生效:设置后立即刷新表头显示,无需额外刷新控件。
4.10.2 关联 API 详解(逐词逐句,零模糊)
1. 设置树形控件单列表头的显示名称:void setHeaderLabel (const QString& text)
函数原型:
void QTreeWidget::setHeaderLabel(const QString& text);
逐词逐句底层解析:
void:无返回值;QTreeWidget:::成员函数;setHeaderLabel():函数名,"设置表头标签" 的意思;const QString& text:入参,表头要显示的文本内容。
参数说明:
text:表头要显示的文本内容,QString类型。
4.10.3 使用示例
#include <QTreeWidget>
#include <QStringList>
// 假设 ui->treeWidget 已经存在
// 示例1:设置单列树形控件的表头名称
ui->treeWidget->setHeaderLabel("文件目录");
// 【补充】多列树形控件的表头设置(用 setHeaderLabels)
// ui->treeWidget->setColumnCount(3); // 先设置 3 列
// QStringList headers = {"名称", "大小", "修改时间"};
// ui->treeWidget->setHeaderLabels(headers);
示例代码:
cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//OK,本文件我们就来学习QTreeWidget的核心方法,添加顶层节点等等~~
//一样,比较简单,唯一就是要注意添加顶层节点这件事~~~
/**
* @class QTreeWidget
* @brief Qt中树形结构展示控件的核心方法,聚焦顶层节点管理、选中控制、结构清理与表头配置
* @details 以下方法覆盖QTreeWidget的核心操作:顶层节点的增删改查、全节点清空、选中节点控制、节点展开/折叠、表头名称设置,是构建和管理树形控件的基础接口;
* 所有顶层节点操作遵循"下标从0开始"的规则,支持动态调整树形控件的顶层结构。
*/
// ============================== 核心方法详解 ==============================
/**
* @fn void QTreeWidget::clear()
* @brief 清空树形控件中**所有节点**(包含顶层节点及所有子节点)
* @details 核心清理方法,删除树形控件中所有顶层节点及其下属的所有子节点,释放所有QTreeWidgetItem的内存,清空后topLevelItemCount()返回0。
*
* @使用示例:
* // 清空树形控件所有节点
* ui->treeWidget->clear();
* qDebug() << "清空后顶层节点数:" << ui->treeWidget->topLevelItemCount(); // 输出:0
*
* 【关键注意事项】
* 1. 内存释放:clear()会自动释放所有节点(顶层+子节点)的内存,无需手动delete;
* 2. 状态重置:清空后树形控件恢复初始状态,表头名称保持不变;
* 3. 不可逆操作:节点删除后无法恢复,需提前备份数据(如需保留节点对象,需先通过takeTopLevelItem移除)。
*/
/**
* @fn void QTreeWidget::addTopLevelItem(QTreeWidgetItem* item)
* @brief 为树形控件**新增顶层节点**(追加到顶层节点列表末尾)
* @details 核心顶层节点添加方法,将item设为树形控件的顶层节点(无父节点),item的所有权移交至树形控件,无需手动管理内存。
*
* @参数说明:
* @param item - QTreeWidgetItem*类型,要添加的顶层节点指针(不可为nullptr)。
*
* @使用示例:
* // 创建并添加顶层节点
* QTreeWidgetItem* topItem = new QTreeWidgetItem();
* topItem->setText(0, "顶层节点1");
* ui->treeWidget->addTopLevelItem(topItem);
*
* // 为顶层节点添加子节点
* QTreeWidgetItem* childItem = new QTreeWidgetItem();
* childItem->setText(0, "子节点1");
* topItem->addChild(childItem);
*
* 【关键注意事项】
* 1. 所有权移交:item的所有权归树形控件,clear()/takeTopLevelItem()会自动/手动释放内存;
* 2. 重复添加:同一item不可重复添加为顶层节点(会导致未定义行为);
* 3. 下标顺序:新增的顶层节点追加到列表末尾,下标为topLevelItemCount()-1。
*/
/**
* @fn QTreeWidgetItem* QTreeWidget::topLevelItem(int index) const
* @brief 按**下标**获取树形控件的指定顶层节点
* @details 精准顶层节点查询方法,返回下标为index的顶层节点指针;index超出有效范围时返回nullptr。
*
* @参数说明:
* @param index - int类型,顶层节点下标(从0开始计数)。
*
* @返回值说明:
* @return QTreeWidgetItem* - 指定下标的顶层节点指针(下标无效返回nullptr)。
*
* @使用示例:
* // 获取第一个顶层节点(下标0)
* QTreeWidgetItem* firstTopItem = ui->treeWidget->topLevelItem(0);
* if (firstTopItem) {
* qDebug() << "第一个顶层节点文本:" << firstTopItem->text(0);
* } else {
* qDebug() << "无第一个顶层节点";
* }
*
* 【关键注意事项】
* 1. 下标规则:有效范围为[0, topLevelItemCount()-1],超出范围返回nullptr;
* 2. 判空强制:获取后需先判空,再操作节点属性/方法,避免空指针崩溃;
* 3. 层级限制:仅返回顶层节点,子节点需通过节点的child()方法获取。
*/
/**
* @fn int QTreeWidget::topLevelItemCount() const
* @brief 获取树形控件的**顶层节点总数**
* @details 核心结构查询方法,返回树形控件中顶层节点的数量(不包含顶层节点的子节点),无顶层节点时返回0。
*
* @返回值说明:
* @return int - 顶层节点个数(≥0)。
*
* @使用示例:
* // 遍历所有顶层节点
* int topCount = ui->treeWidget->topLevelItemCount();
* qDebug() << "顶层节点总数:" << topCount;
* for (int i = 0; i < topCount; ++i) {
* QTreeWidgetItem* topItem = ui->treeWidget->topLevelItem(i);
* if (topItem) {
* qDebug() << "第" << i+1 << "个顶层节点:" << topItem->text(0);
* }
* }
*
* 【关键注意事项】
* 1. 层级限制:仅统计顶层节点,子节点数量需通过节点的childCount()获取;
* 2. 实时更新:添加/删除顶层节点(addTopLevelItem/takeTopLevelItem)后立即更新;
* 3. 空节点计数:即使顶层节点无文本/子节点,仍计入总数。
*/
/**
* @fn int QTreeWidget::indexOfTopLevelItem(QTreeWidgetItem* item) const
* @brief 查询指定节点在**顶层节点列表中的下标**
* @details 反向查询方法,返回item作为顶层节点的下标;item不是顶层节点/为nullptr时返回-1。
*
* @参数说明:
* @param item - QTreeWidgetItem*类型,要查询的节点指针。
*
* @返回值说明:
* @return int - 顶层节点下标(0开始,非顶层节点/无效item返回-1)。
*
* @使用示例:
* // 创建并添加顶层节点,查询其下标
* QTreeWidgetItem* topItem = new QTreeWidgetItem();
* topItem->setText(0, "测试顶层节点");
* ui->treeWidget->addTopLevelItem(topItem);
*
* int index = ui->treeWidget->indexOfTopLevelItem(topItem);
* if (index != -1) {
* qDebug() << "节点下标:" << index;
* } else {
* qDebug() << "该节点不是顶层节点";
* }
*
* 【关键注意事项】
* 1. 匹配规则:仅匹配**直接顶层节点**,子节点/其他树形控件的节点返回-1;
* 2. 时效性:节点被移除(takeTopLevelItem)后,查询其下标返回-1;
* 3. 空指针:传入nullptr时返回-1,无需额外判空。
*/
/**
* @fn QTreeWidgetItem* QTreeWidget::takeTopLevelItem(int index)
* @brief 按**下标**删除树形控件的指定顶层节点,并返回被删除的节点指针
* @details 核心顶层节点删除方法,仅将节点从顶层列表中移除(不自动释放内存),需手动delete返回的指针避免内存泄漏。
*
* @参数说明:
* @param index - int类型,要删除的顶层节点下标(从0开始计数)。
*
* @返回值说明:
* @return QTreeWidgetItem* - 被删除的顶层节点指针(下标无效返回nullptr)。
*
* @使用示例:
* // 删除第一个顶层节点并释放内存
* QTreeWidgetItem* deletedItem = ui->treeWidget->takeTopLevelItem(0);
* if (deletedItem) {
* qDebug() << "删除的顶层节点:" << deletedItem->text(0);
* delete deletedItem; // 必须手动释放,否则内存泄漏
* deletedItem = nullptr;
* }
*
* 【关键注意事项】
* 1. 内存管理:takeTopLevelItem仅"移除"节点,**需手动delete返回指针**;
* 2. 下标偏移:删除后后续顶层节点下标自动-1(如删除下标1,原下标2变为下标1);
* 3. 子节点联动:被移除的顶层节点仍包含其所有子节点,可重新添加到树形控件/其他节点下。
*/
/**
* @fn QTreeWidgetItem* QTreeWidget::currentItem() const
* @brief 获取树形控件中**当前选中的节点**
* @details 核心选中状态查询方法,返回当前激活选中的节点指针(可为顶层节点/子节点);无选中节点时返回nullptr。
*
* @返回值说明:
* @return QTreeWidgetItem* - 当前选中节点指针(无选中返回nullptr)。
*
* @使用示例:
* // 获取当前选中节点并打印其文本
* QTreeWidgetItem* selItem = ui->treeWidget->currentItem();
* if (selItem) {
* qDebug() << "当前选中节点:" << selItem->text(0);
* // 额外获取选中节点的父节点
* QTreeWidgetItem* parentItem = selItem->parent();
* if (parentItem) {
* qDebug() << "选中节点的父节点:" << parentItem->text(0);
* } else {
* qDebug() << "选中节点为顶层节点";
* }
* } else {
* qDebug() << "无选中节点";
* }
*
* 【关键注意事项】
* 1. 判空必须:无选中节点时返回nullptr,直接操作会导致崩溃;
* 2. 选中范围:可返回顶层节点或任意层级的子节点,不限于顶层;
* 3. 选择模式:受setSelectionMode()影响,无选择权限时始终返回nullptr。
*/
/**
* @fn void QTreeWidget::setCurrentItem(QTreeWidgetItem* item)
* @brief 将树形控件中指定节点设为**当前选中节点**
* @details 核心选中控制方法,选中指定的节点(可为顶层/子节点);item为nullptr时取消所有选中。
*
* @参数说明:
* @param item - QTreeWidgetItem*类型,要选中的节点指针(nullptr取消选中)。
*
* @使用示例:
* // 选中第一个顶层节点
* QTreeWidgetItem* targetItem = ui->treeWidget->topLevelItem(0);
* if (targetItem) {
* ui->treeWidget->setCurrentItem(targetItem);
* }
*
* // 取消所有选中
* // ui->treeWidget->setCurrentItem(nullptr);
*
* 【关键注意事项】
* 1. 有效性校验:item需是当前树形控件的节点(顶层/子节点),否则设置无效;
* 2. 信号触发:设置后会触发itemSelectionChanged()信号;
* 3. 视觉反馈:选中的节点会按系统/QSS样式高亮显示。
*/
/**
* @fn void QTreeWidget::setExpanded(const QModelIndex &index, bool expand)
* @brief (标准方法签名)展开/折叠指定节点对应的索引项
* @details 节点展开/折叠控制方法,用户写的`setExpanded(bool)`为简化表述,实际需先通过indexFromItem()获取节点索引再调用;
* 推荐直接使用`QTreeWidgetItem::setExpanded(bool)`,更直观控制节点展开/折叠(expand=true展开,false折叠)。
*
* @使用示例(推荐:节点直接调用):
* // 展开第一个顶层节点
* QTreeWidgetItem* topItem = ui->treeWidget->topLevelItem(0);
* if (topItem) {
* topItem->setExpanded(true); // 展开节点(显示子节点)
* // topItem->setExpanded(false); // 折叠节点(隐藏子节点)
* }
*
* @使用示例(控件方法):
* QTreeWidgetItem* topItem = ui->treeWidget->topLevelItem(0);
* if (topItem) {
* QModelIndex index = ui->treeWidget->indexFromItem(topItem);
* ui->treeWidget->setExpanded(index, true);
* }
*
* 【关键注意事项】
* 1. 无意义场景:无子女节点的节点,展开/折叠无视觉变化;
* 2. 信号联动:状态变更触发itemExpanded()/itemCollapsed()信号;
* 3. 简化操作:优先使用节点的setExpanded(bool),无需转换索引,更简洁。
*/
/**
* @fn void QTreeWidget::setHeaderLabel(const QString& text)
* @brief 设置树形控件**单列表头的显示名称**
* @details 表头配置方法,适用于单列树形控件,设置表头(列标题)的文本;多列树形控件需使用setHeaderLabels(const QStringList&)。
*
* @参数说明:
* @param text - QString类型,表头要显示的文本内容。
*
* @使用示例:
* // 设置单列树形控件的表头名称
* ui->treeWidget->setHeaderLabel("文件目录");
*
* // 多列表头补充设置
* // QStringList headers = {"名称", "大小", "修改时间"};
* // ui->treeWidget->setHeaderLabels(headers);
*
* 【关键注意事项】
* 1. 列数适配:仅适用于单列树形控件(columnCount()=1),多列需用setHeaderLabels;
* 2. 视觉控制:表头显示在控件顶部,可通过setHeaderHidden(true)隐藏;
* 3. 动态生效:设置后立即刷新表头显示,无需额外刷新控件。
*/
}
Widget::~Widget()
{
delete ui;
}
第五章 QTreeWidget 核心交互信号详解
讲完了所有核心方法,我们最后来讲 QTreeWidget 的核心交互信号------ 这些信号是 QTreeWidget 与业务逻辑联动的核心桥梁,覆盖选中切换、点击、双击、鼠标悬浮、展开 / 折叠等核心场景。
我们讲:currentItemChanged、itemClicked、itemDoubleClicked、itemEntered、itemExpanded、itemCollapsed。
5.1 信号一:currentItemChanged (QTreeWidgetItem* current, QTreeWidgetItem* old)------ 切换选中节点时触发
5.1.1 信号的核心定义
currentItemChanged 是 QTreeWidget 最核心、最常用 的选中变更信号 ------ 它在选中不同节点时触发(选中同一条目不触发),同时返回 "当前选中节点" 和 "上一个选中节点"。
通俗理解:currentItemChanged 就像 "树形控件上标亮的节点变了时通知你"------ 它会告诉你 "之前标亮的是哪个节点,现在标亮的是哪个节点";如果你重复点击同一个节点,它不会通知你,因为标亮的节点没变。
触发场景包括:
- 用户点击不同节点;
- 代码调用
setCurrentItem(); - 删除选中节点。
这里有几个超级重要的规则,必须牢记,刻在脑子里:
- 判空强制!(超级重要!说三遍!) :
current/old可能为nullptr!- 比如首次选中时,
old为nullptr; - 比如取消选中时,
current为nullptr; - 必须先判空再操作!
- 触发规则(超级重要!) :
- 仅选中不同节点时触发!
- 重复选中同一条目不触发!
- 代码触发(超级重要!) :
- 调用
setCurrentItem()也会触发此信号! - 这点和
itemClicked不一样!
- 调用
- 取消选中 :删除选中节点时,
current为nullptr,old为原选中节点。
5.1.2 信号参数详解
信号原型:
void QTreeWidget::currentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* old);
参数说明:
current:QTreeWidgetItem*类型,当前选中的节点;- 无选中时为
nullptr;
- 无选中时为
old:QTreeWidgetItem*类型,上一个选中的节点;- 无之前选中项时为
nullptr。
- 无之前选中项时为
5.1.3 使用示例
#include <QTreeWidgetItem>
#include <QTreeWidget>
#include <QDebug>
#include <QObject> // connect
// 假设 ui->treeWidget 已经存在,并且在 Widget 类的构造函数中
// 绑定信号,打印选中节点的切换记录
connect(ui->treeWidget, &QTreeWidget::currentItemChanged,
this, [=](QTreeWidgetItem* cur, QTreeWidgetItem* prev){
// 处理上一个选中节点
QString prevText = (prev != nullptr) ? prev->text(0) : "无";
// 处理当前选中节点
QString curText = (cur != nullptr) ? cur->text(0) : "无";
// 打印变更记录
qDebug() << "选中节点变更:" << prevText << " → " << curText;
});
5.2 信号二:itemClicked (QTreeWidgetItem* item, int col)------ 用户鼠标单击节点时触发
5.2.1 信号的核心定义
itemClicked 是 QTreeWidget 纯交互触发 的信号 ------ 它仅响应用户鼠标单击节点操作,代码选中节点不触发,返回被点击的节点对象及点击的列号。
通俗理解:itemClicked 就像 "用户用鼠标点了树形控件里的某个节点时通知你"------ 它会告诉你 "点的是哪个节点,点的是第几列";只响应用户的点击,你用代码选中节点它不会通知你。
这里有几个超级重要的规则,必须牢记:
- 触发条件(超级重要!) :
- 仅用户单击触发!
- 代码选中节点(
setCurrentItem)不触发! - 这点和
currentItemChanged不一样!
- 参数有效性(超级重要!) :
item始终为有效节点(无需判空)!col为节点的有效列号(从 0 开始)!- 点击节点空白区域(无列内容处)默认返回第 0 列!
- 点击树形控件空白处不触发!
- 选中联动(超级重要!) :
- 单击节点会自动将其设为当前选中节点!
- 因此会先触发
itemClicked(),再触发currentItemChanged()!
- 重复点击同一条目也触发(超级重要!) :
- 哪怕节点已经是选中项,再次点击也会触发
itemClicked()! - 这点和
currentItemChanged不一样!
- 哪怕节点已经是选中项,再次点击也会触发
- 多列适配 :多列树形结构中,点击不同列会返回对应
col值,单列默认返回 0。
5.2.2 信号参数详解
信号原型:
void QTreeWidget::itemClicked(QTreeWidgetItem* item, int column);
参数说明:
item:QTreeWidgetItem*类型,被单击的节点;- 不会为
nullptr;
- 不会为
column:int类型,点击的列号;- 从 0 开始计数。
5.2.3 使用示例
#include <QTreeWidgetItem>
#include <QTreeWidget>
#include <QDebug>
#include <QObject>
// 假设 ui->treeWidget 已经存在,并且在 Widget 类的构造函数中
// 绑定信号,单击节点时修改对应列文本
connect(ui->treeWidget, &QTreeWidget::itemClicked,
this, [=](QTreeWidgetItem* clickedItem, int col){
qDebug() << "单击节点:" << clickedItem->text(0) << ",列号:" << col;
// 修改点击列的文本
clickedItem->setText(col, "已单击");
});
5.3 信号三:itemDoubleClicked (QTreeWidgetItem* item, int col)------ 用户鼠标双击节点时触发
5.3.1 信号的核心定义
itemDoubleClicked 是 QTreeWidget 适配 "双击节点执行核心操作" 场景的信号 ------ 它仅响应用户鼠标双击操作,代码操作 / 单击均不触发,返回被双击的节点对象及列号。
通俗理解:itemDoubleClicked 就像 "用户用鼠标快速双击了树形控件里的某个节点时通知你"------ 它适合做 "编辑节点""打开详情""查看关联数据" 这种需要双击确认的操作。
这里有几个超级重要的规则,必须牢记:
- 触发顺序(超级重要!) :
- 双击会先触发
itemClicked()(第一次单击),再触发此信号! - 如果你同时绑定了这两个信号,要注意逻辑冲突!
- 双击会先触发
- 触发条件(超级重要!) :
- 仅用户双击触发!
- 代码操作 / 单击均不触发!
- 参数有效性 :
item无需判空,col为有效列号。
5.3.2 信号参数详解
信号原型:
void QTreeWidget::itemDoubleClicked(QTreeWidgetItem* item, int column);
参数说明:
item:QTreeWidgetItem*类型,被双击的节点;- 不会为
nullptr;
- 不会为
column:int类型,双击的列号;- 从 0 开始计数。
5.3.3 使用示例
#include <QTreeWidgetItem>
#include <QTreeWidget>
#include <QInputDialog>
#include <QLineEdit>
#include <QObject>
// 假设 ui->treeWidget 已经存在,并且在 Widget 类的构造函数中
// 绑定信号,双击节点时编辑对应列文本
connect(ui->treeWidget, &QTreeWidget::itemDoubleClicked,
this, [=](QTreeWidgetItem* doubleItem, int col){
// 弹出输入框编辑文本
QString newText = QInputDialog::getText(this, "编辑节点", "修改内容:",
QLineEdit::Normal, doubleItem->text(col));
if (!newText.isEmpty()) {
doubleItem->setText(col, newText);
}
});
5.4 信号四:itemEntered (QTreeWidgetItem* item, int col)------ 鼠标光标进入节点区域时触发
5.4.1 信号的核心定义
itemEntered 是 QTreeWidget 用于鼠标悬浮交互 的信号 ------ 它在鼠标光标进入节点区域时触发,需开启鼠标跟踪才会触发!
通俗理解:itemEntered 就像 "鼠标移到树形控件里的某个节点上时通知你"------ 你可以用它做 "鼠标悬浮高亮节点""显示 Tooltip 提示" 等效果;但注意,你必须先开启鼠标跟踪,否则它不会通知你!
这里有几个超级重要的规则,必须牢记,刻在脑子里:
- 前置条件!(超级重要!说三遍!) :
- 必须调用
setMouseTracking(true)! - 否则永不触发此信号!
- 这是新手最容易忽略的!
- 必须调用
- 触发频率(超级重要!) :
- 鼠标在节点间移动时高频触发!
- 避免在信号槽内执行耗时操作!
- 仅进不出(超级重要!) :
- 此信号仅响应 "鼠标进入" 节点!
- 鼠标离开节点需结合
QMouseEvent手动处理! - 没有
itemLeft信号!
- 参数有效性 :
item无需判空,col为有效列号。
5.4.2 信号参数详解
信号原型:
void QTreeWidget::itemEntered(QTreeWidgetItem* item, int column);
参数说明:
item:QTreeWidgetItem*类型,鼠标进入的节点;- 不会为
nullptr;
- 不会为
column:int类型,鼠标进入的列号;- 从 0 开始计数。
5.4.3 使用示例
#include <QTreeWidgetItem>
#include <QTreeWidget>
#include <QGuiApplication> // Qt::lightGray
#include <QObject>
// 假设 ui->treeWidget 已经存在,并且在 Widget 类的构造函数中
// 【必须!】第一步:开启树形控件的鼠标跟踪!
ui->treeWidget->setMouseTracking(true);
// 第二步:绑定信号,悬浮时高亮节点背景
connect(ui->treeWidget, &QTreeWidget::itemEntered,
this, [=](QTreeWidgetItem* enterItem, int col){
// 悬浮列设浅灰背景
enterItem->setBackground(col, Qt::lightGray);
// 注意:鼠标离开时恢复背景需结合 QMouseEvent 手动处理
});
5.5 信号五:itemExpanded (QTreeWidgetItem* item)------ 树形节点被展开时触发
5.5.1 信号的核心定义
itemExpanded 是 QTreeWidget 节点展开专属 的信号 ------ 它在节点从 "折叠" 变为 "展开" 时触发,返回被展开的节点对象;触发场景包括用户点击节点展开图标、代码调用 setExpanded(true)。
通俗理解:itemExpanded 就像 "用户打开了某个文件夹时通知你"------ 它会告诉你 "打开的是哪个文件夹";你可以用它做 "懒加载"(打开文件夹时才去加载子节点,节省内存和时间)。
这里有几个超级重要的规则,必须牢记:
- 触发条件 :
- 节点从 "折叠" 变为 "展开" 时触发!
- 无子女节点的节点展开不触发!
- 参数有效性 :
item始终为有效节点(无需判空); - 双向触发 :用户操作 / 代码调用
setExpanded(true)均会触发。
5.5.2 信号参数详解
信号原型:
void QTreeWidget::itemExpanded(QTreeWidgetItem* item);
参数说明:
item:QTreeWidgetItem*类型,被展开的节点;- 不会为
nullptr。
- 不会为
5.5.3 使用示例
#include <QTreeWidgetItem>
#include <QTreeWidget>
#include <QDebug>
#include <QObject>
// 假设 ui->treeWidget 已经存在,并且在 Widget 类的构造函数中
// 绑定信号,节点展开时打印提示
connect(ui->treeWidget, &QTreeWidget::itemExpanded,
this, [=](QTreeWidgetItem* expandItem){
qDebug() << "节点已展开:" << expandItem->text(0);
qDebug() << " 子节点数量:" << expandItem->childCount();
// 【典型用法】懒加载:如果子节点是空的,此时去加载子节点
// if (expandItem->childCount() == 0) {
// loadChildren(expandItem); // 自定义加载函数
// }
});
5.6 信号六:itemCollapsed (QTreeWidgetItem* item)------ 树形节点被折叠时触发
5.6.1 信号的核心定义
首先再次纠正笔误:你提供的资料里写的 itemCollapsend 是错误的!Qt 官方的正确信号名是 itemCollapsed(注意是 'l' 不是's')!
itemCollapsed 是 QTreeWidget 节点折叠专属 的信号 ------ 它在节点从 "展开" 变为 "折叠" 时触发,返回被折叠的节点对象;触发场景包括用户点击节点折叠图标、代码调用 setExpanded(false)。
通俗理解:itemCollapsed 就像 "用户合上了某个文件夹时通知你"------ 它会告诉你 "合上的是哪个文件夹";你可以用它做 "释放内存"(合上文件夹时清除子节点,下次打开再重新加载)。
这里有几个超级重要的规则,必须牢记:
- 笔误纠正 :正确信号名为
itemCollapsed,非itemCollapsend; - 触发条件 :
- 节点从 "展开" 变为 "折叠" 时触发!
- 无子女节点的节点折叠不触发!
- 参数有效性 :
item始终为有效节点(无需判空); - 双向触发 :用户操作 / 代码调用
setExpanded(false)均会触发。
5.6.2 信号参数详解
信号原型:
void QTreeWidget::itemCollapsed(QTreeWidgetItem* item);
参数说明:
item:QTreeWidgetItem*类型,被折叠的节点;- 不会为
nullptr。
- 不会为
5.6.3 使用示例
#include <QTreeWidgetItem>
#include <QTreeWidget>
#include <QDebug>
#include <QObject>
// 假设 ui->treeWidget 已经存在,并且在 Widget 类的构造函数中
// 绑定信号,节点折叠时打印提示
connect(ui->treeWidget, &QTreeWidget::itemCollapsed,
this, [=](QTreeWidgetItem* collapseItem){
qDebug() << "节点已折叠:" << collapseItem->text(0);
// 【典型用法】释放内存:如果子节点非常多,折叠时可以清除子项
// qDeleteAll(collapseItem->takeChildren());
});
示例代码:
cpp
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//OK,本文件我们来学习QTreeWidget的信号
//依旧是使用ui界面
/**
* @class QTreeWidget
* @brief Qt中树形控件的核心交互信号,覆盖选中切换、点击、双击、悬浮、展开/折叠等核心场景
* @details 这些信号是QTreeWidget与业务逻辑联动的核心接口,所有信号均返回触发交互的节点对象及列号(col);
* 注:`itemCollapsend`为笔误,正确信号名为`itemCollapsed`,以下按官方正确名称解析。
*
* 【核心特征】
* 1. 选中交互:支持选中节点切换时触发信号,返回当前/之前选中节点;
* 2. 点击交互:支持单击/双击节点触发信号,返回目标节点及点击列号;
* 3. 悬浮交互:支持鼠标进入节点触发信号(需开启鼠标跟踪);
* 4. 展开折叠:支持节点展开/折叠时触发专属信号,适配树形结构交互逻辑。
*/
// ============================== 核心信号详解 ==============================
/**
* @signal void QTreeWidget::currentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* old)
* @brief 切换**选中节点**时触发的信号(选中同一条目不触发)
* @details 核心选中变更信号,同时返回"当前选中节点"和"上一个选中节点";
* 触发场景包括用户点击不同节点、代码设置选中节点、删除选中节点等。
*
* @参数说明:
* @param current - QTreeWidgetItem*类型,当前选中的节点(无选中时为nullptr);
* @param old - QTreeWidgetItem*类型,上一个选中的节点(无之前选中项时为nullptr)。
*
* @使用示例:
* // 绑定信号,打印选中节点的切换记录
* connect(ui->treeWidget, &QTreeWidget::currentItemChanged, this,
* [=](QTreeWidgetItem* cur, QTreeWidgetItem* prev){
* QString prevText = prev ? prev->text(0) : "无";
* QString curText = cur ? cur->text(0) : "无";
* qDebug() << "选中节点变更:" << prevText << " → " << curText;
* });
*
* 【关键注意事项】
* 1. 判空强制:current/old可能为nullptr(首次选中/取消选中),必须先判空再操作;
* 2. 触发规则:仅选中**不同**节点时触发(重复点击同一条目不触发);
* 3. 代码触发:调用setCurrentItem()也会触发此信号;
* 4. 取消选中:删除选中节点时,current为nullptr,old为原选中节点。
*/
/**
* @signal void QTreeWidget::itemClicked(QTreeWidgetItem* item, int col)
* @brief **用户鼠标单击**树形节点时触发的信号
* @details 纯交互触发信号,仅响应用户单击节点操作,返回被点击的节点对象及点击的列号;
* 点击节点空白区域(无列内容处)默认返回第0列,点击树形控件空白处不触发。
*
* @参数说明:
* @param item - QTreeWidgetItem*类型,被单击的节点(不会为nullptr);
* @param col - int类型,点击的列号(从0开始计数)。
*
* @使用示例:
* // 绑定信号,单击节点时修改对应列文本
* connect(ui->treeWidget, &QTreeWidget::itemClicked, this,
* [=](QTreeWidgetItem* clickedItem, int col){
* qDebug() << "单击节点:" << clickedItem->text(0) << ",列号:" << col;
* clickedItem->setText(col, "已单击");
* });
*
* 【关键注意事项】
* 1. 触发条件:仅用户**单击**触发,代码选中节点(setCurrentItem)不触发;
* 2. 参数有效性:item始终为有效节点(无需判空),col为节点的有效列号;
* 3. 选中联动:单击节点会自动将其设为当前选中节点,因此先触发itemClicked(),再触发currentItemChanged();
* 4. 多列适配:多列树形结构中,点击不同列会返回对应col值,单列默认返回0。
*/
/**
* @signal void QTreeWidget::itemDoubleClicked(QTreeWidgetItem* item, int col)
* @brief **用户鼠标双击**树形节点时触发的信号
* @details 适配"双击节点执行核心操作"的场景(如编辑节点、打开详情),返回被双击的节点对象及列号。
*
* @参数说明:
* @param item - QTreeWidgetItem*类型,被双击的节点(不会为nullptr);
* @param col - int类型,双击的列号(从0开始计数)。
*
* @使用示例:
* // 绑定信号,双击节点时编辑对应列文本
* connect(ui->treeWidget, &QTreeWidget::itemDoubleClicked, this,
* [=](QTreeWidgetItem* doubleItem, int col){
* QString newText = QInputDialog::getText(this, "编辑节点", "修改内容:",
* QLineEdit::Normal, doubleItem->text(col));
* if (!newText.isEmpty()) {
* doubleItem->setText(col, newText);
* }
* });
*
* 【关键注意事项】
* 1. 触发顺序:双击会先触发itemClicked()(第一次单击),再触发此信号;
* 2. 触发条件:仅用户**双击**触发,代码操作/单击均不触发;
* 3. 参数有效性:item无需判空,col为有效列号;
* 4. 交互场景:适合"编辑节点内容、打开关联数据、展示详情弹窗"等操作。
*/
/**
* @signal void QTreeWidget::itemEntered(QTreeWidgetItem* item, int col)
* @brief **鼠标光标进入**树形节点区域时触发的信号(需开启鼠标跟踪)
* @details 悬浮交互信号,用于实现"鼠标悬浮高亮节点、显示提示信息"等效果;
* 默认关闭鼠标跟踪,需手动调用setMouseTracking(true)才会触发。
*
* @参数说明:
* @param item - QTreeWidgetItem*类型,鼠标进入的节点(不会为nullptr);
* @param col - int类型,鼠标进入的列号(从0开始计数)。
*
* @使用示例:
* // 第一步:开启树形控件的鼠标跟踪
* ui->treeWidget->setMouseTracking(true);
* // 第二步:绑定信号,悬浮时高亮节点背景
* connect(ui->treeWidget, &QTreeWidget::itemEntered, this,
* [=](QTreeWidgetItem* enterItem, int col){
* enterItem->setBackground(col, Qt::lightGray); // 悬浮列设浅灰背景
* });
*
* 【关键注意事项】
* 1. 前置条件:必须调用setMouseTracking(true),否则永不触发此信号;
* 2. 触发频率:鼠标在节点间移动时高频触发,避免执行耗时操作;
* 3. 仅进不出:此信号仅响应"鼠标进入",鼠标离开节点需结合QMouseEvent手动处理;
* 4. 参数有效性:item无需判空,col为有效列号。
*/
/**
* @signal void QTreeWidget::itemExpanded(QTreeWidgetItem* item)
* @brief 树形节点**被展开**时触发的信号
* @details 节点展开专属信号,返回被展开的节点对象;触发场景包括用户点击节点展开图标、代码调用setExpanded(true)。
*
* @参数说明:
* @param item - QTreeWidgetItem*类型,被展开的节点(不会为nullptr)。
*
* @使用示例:
* // 绑定信号,节点展开时打印提示
* connect(ui->treeWidget, &QTreeWidget::itemExpanded, this,
* [=](QTreeWidgetItem* expandItem){
* qDebug() << "节点已展开:" << expandItem->text(0);
* });
*
* 【关键注意事项】
* 1. 触发条件:节点从"折叠"变为"展开"时触发,无子女节点的节点展开不触发;
* 2. 参数有效性:item始终为有效节点(无需判空);
* 3. 双向触发:用户操作/代码调用setExpanded(true)均会触发。
*/
/**
* @signal void QTreeWidget::itemCollapsed(QTreeWidgetItem* item)
* @brief 树形节点**被折叠**时触发的信号(注:原名称itemCollapsend为笔误,此为官方正确名称)
* @details 节点折叠专属信号,返回被折叠的节点对象;触发场景包括用户点击节点折叠图标、代码调用setExpanded(false)。
*
* @参数说明:
* @param item - QTreeWidgetItem*类型,被折叠的节点(不会为nullptr)。
*
* @使用示例:
* // 绑定信号,节点折叠时打印提示
* connect(ui->treeWidget, &QTreeWidget::itemCollapsed, this,
* [=](QTreeWidgetItem* collapseItem){
* qDebug() << "节点已折叠:" << collapseItem->text(0);
* });
*
* 【关键注意事项】
* 1. 笔误纠正:正确信号名为itemCollapsed,非itemCollapsend;
* 2. 触发条件:节点从"展开"变为"折叠"时触发,无子女节点的节点折叠不触发;
* 3. 参数有效性:item始终为有效节点(无需判空);
* 4. 双向触发:用户操作/代码调用setExpanded(false)均会触发。
*/
// 创建一个空节点,稍后设置文本
QTreeWidgetItem* item2 = new QTreeWidgetItem();
item2->setText(0, "我是第一列的内容");
QTreeWidgetItem* item2_1 = new QTreeWidgetItem();
item2_1->setText(0, "我是第一列的子节点");
//添加子节点进去
item2->addChild(item2_1);
// 添加到树控件
ui->tw->addTopLevelItem(item2);
}
Widget::~Widget()
{
delete ui;
}
// 1. 当前选中项改变
void Widget::on_tw_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
{
// 触发时机:当焦点框(选中状态)从一个节点移动到另一个节点时。
// 注意:current 或 previous 可能为 nullptr (例如刚打开窗口或取消选中时)。
if (current) {
int colCount = ui->tw->columnCount();
qDebug() << "[Tree Current Changed] 新选中节点:";
// 遍历打印当前节点所有列的内容
for (int i = 0; i < colCount; ++i) {
qDebug() << " 列" << i << ":" << current->text(i);
}
// 典型用法:
// 1. 根据选中的节点,在右侧详情面板加载数据。
// 2. 判断节点类型(通过 data 存储的类型标识),显示不同的操作按钮。
// 示例:获取隐藏数据
// QVariant typeId = current->data(0, Qt::UserRole);
} else {
qDebug() << "[Tree Current Changed] 已取消所有选中";
// 清空详情面板
}
if (previous) {
// 如果需要处理"离开"旧节点的逻辑(如保存临时编辑),可以在这里写
}
}
// 2. 节点被单击
void Widget::on_tw_itemClicked(QTreeWidgetItem *item, int column)
{
// 触发时机:鼠标左键单击某个节点。
// 关键参数:column 告诉你是点击了哪一列 (0, 1, 2...)
if (!item) return;
QString content = item->text(column);
qDebug() << "[Tree Clicked] 点击了 -> 列:" << column << ", 内容:" << content;
// 典型用法:
// 1. 复选框逻辑:如果第 0 列有复选框,点击时切换状态。
if (column == 0 && item->checkState(0) != Qt::Unchecked) {
// 处理勾选逻辑
Qt::CheckState state = (item->checkState(0) == Qt::Checked) ? Qt::Unchecked : Qt::Checked;
item->setCheckState(0, state);
}
// 2. 特定列点击事件:例如点击"大小"列进行排序,或点击"操作"列弹出菜单。
if (column == 2) {
// 假设第3列是操作列
// showContextMenu(item);
}
}
// 3. 节点被双击
void Widget::on_tw_itemDoubleClicked(QTreeWidgetItem *item, int column)
{
// 触发时机:快速双击节点。
if (!item) return;
qDebug() << "[Tree Double Clicked] 双击了 -> 列:" << column << ", 文本:" << item->text(0);
// 典型用法:
// 1. 展开/折叠:如果节点有子节点但没展开,双击通常默认会展开。
// 如果你想自定义:比如双击文件夹打开新窗口,而不是展开。
if (item->childCount() > 0) {
item->setExpanded(!item->isExpanded());
} else {
// 如果是叶子节点(如文件),执行打开操作
qDebug() << "打开文件/详情页:" << item->text(0);
// openFile(item->data(0, Qt::UserRole).toString());
}
}
// 4. 鼠标移入节点
void Widget::on_tw_itemEntered(QTreeWidgetItem *item, int column)
{
// 触发时机:鼠标光标移入节点区域。
// 注意:需要在 UI 设计器中勾选 treeWidget 的 "mouseTracking" 属性,
// 或者代码设置: ui->tw->viewport()->setMouseTracking(true);
if (!item) return;
// 典型用法:
// 1. 显示 Tooltip,特别是当文字被截断时。
QString fullText = item->text(column);
if (item->font(column).bold()) {
fullText += " (加粗项)";
}
item->setToolTip(column, fullText);
// 2. 高亮整行 (可选,通常用 StyleSheet 更好,这里演示逻辑)
// item->setBackground(column, QBrush(QColor("#E3F2FD")));
}
// 5. 节点被展开
void Widget::on_tw_itemExpanded(QTreeWidgetItem *item)
{
// 触发时机:用户点击箭头或通过代码 setExpanded(true) 导致节点展开时。
if (!item) return;
qDebug() << "[Tree Expanded] 展开了节点:" << item->text(0);
qDebug() << " 子节点数量:" << item->childCount();
// 典型用法:
// 1. 懒加载 (Lazy Loading):如果子节点是空的,此时去数据库或文件系统加载子节点。
if (item->childCount() == 0 && item->data(0, Qt::UserRole).toString() == "need_load") {
loadChildrenFromDatabase(item); // 自定义加载函数
item->setData(0, Qt::UserRole, "loaded"); // 标记已加载,防止重复加载
}
}
// 6. 节点被折叠
void Widget::on_tw_itemCollapsed(QTreeWidgetItem *item)
{
// 触发时机:用户点击箭头收起节点时。
if (!item) return;
qDebug() << "[Tree Collapsed] 折叠了节点:" << item->text(0);
// 典型用法:
// 1. 释放内存:如果子节点非常多且占用内存大,折叠时可以清除子项,下次展开再重新加载。
// if (m_memoryPressureHigh) {
// qDeleteAll(item->takeChildren());
// item->setData(0, Qt::UserRole, "need_load");
// }
}
// --- 辅助函数示例 (懒加载) ---
void Widget::loadChildrenFromDatabase(QTreeWidgetItem *parent)
{
// 模拟从数据库加载
QStringList fakeData = {"子项 A", "子项 B", "子项 C"};
for (const QString& text : fakeData) {
QTreeWidgetItem* child = new QTreeWidgetItem(parent);
child->setText(0, text);
child->setText(1, "自动加载的数据");
// 可以继续给 child 设置 "need_load" 标记以实现多层懒加载
}
}
第六章 综合示例:简单的文件目录树
讲完了所有内容,我们最后来做一个综合示例,结合你提供的资料,实现一个简单的 "文件目录树"------ 这是 QTreeWidget 最经典的应用场景之一。
6.1 场景描述
界面上有:
- 一个 QTreeWidget(
objectName为treeWidget); - 表头设置为 "文件目录"。
功能:
- 初始化树形控件:添加 "我的电脑" 作为顶层节点;
- 给 "我的电脑" 添加子节点:"C 盘""D 盘";
- 给 "C 盘" 添加子节点:"Program Files""Users";
- 给 "D 盘" 添加子节点:"文档""图片";
- 展开 "我的电脑" 和 "C 盘";
- 绑定交互信号:选中变更、点击、展开 / 折叠时打印日志。
6.2 代码实现
#include "widget.h"
#include "ui_widget.h"
#include <QTreeWidgetItem>
#include <QTreeWidget>
#include <QDebug>
#include <QObject>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// ================= 1. 设置表头 =================
ui->treeWidget->setHeaderLabel("文件目录");
// ================= 2. 创建顶层节点:我的电脑 =================
QTreeWidgetItem* myComputer = new QTreeWidgetItem();
myComputer->setText(0, "我的电脑");
ui->treeWidget->addTopLevelItem(myComputer);
// ================= 3. 给"我的电脑"添加子节点:C 盘、D 盘 =================
QTreeWidgetItem* driveC = new QTreeWidgetItem();
driveC->setText(0, "C 盘");
myComputer->addChild(driveC);
QTreeWidgetItem* driveD = new QTreeWidgetItem();
driveD->setText(0, "D 盘");
myComputer->addChild(driveD);
// ================= 4. 给"C 盘"添加子节点 =================
QTreeWidgetItem* programFiles = new QTreeWidgetItem();
programFiles->setText(0, "Program Files");
driveC->addChild(programFiles);
QTreeWidgetItem* users = new QTreeWidgetItem();
users->setText(0, "Users");
driveC->addChild(users);
// ================= 5. 给"D 盘"添加子节点 =================
QTreeWidgetItem* docs = new QTreeWidgetItem();
docs->setText(0, "文档");
driveD->addChild(docs);
QTreeWidgetItem* pics = new QTreeWidgetItem();
pics->setText(0, "图片");
driveD->addChild(pics);
// ================= 6. 展开节点 =================
myComputer->setExpanded(true); // 展开"我的电脑"
driveC->setExpanded(true); // 展开"C 盘"
// ================= 7. 绑定交互信号 =================
// 信号 1:选中变更
connect(ui->treeWidget, &QTreeWidget::currentItemChanged,
this, [=](QTreeWidgetItem* cur, QTreeWidgetItem* prev){
QString prevText = prev ? prev->text(0) : "无";
QString curText = cur ? cur->text(0) : "无";
qDebug() << "[选中变更]" << prevText << "→" << curText;
});
// 信号 2:点击节点
connect(ui->treeWidget, &QTreeWidget::itemClicked,
this, [=](QTreeWidgetItem* item, int col){
qDebug() << "[点击]" << item->text(col) << ",列:" << col;
});
// 信号 3:节点展开
connect(ui->treeWidget, &QTreeWidget::itemExpanded,
this, [=](QTreeWidgetItem* item){
qDebug() << "[展开]" << item->text(0);
});
// 信号 4:节点折叠
connect(ui->treeWidget, &QTreeWidget::itemCollapsed,
this, [=](QTreeWidgetItem* item){
qDebug() << "[折叠]" << item->text(0);
});
}
Widget::~Widget()
{
delete ui;
}
第七章 全文总结与学习建议
恭喜你!终于看完了这篇QTreeWidget 与 QTreeWidgetItem 详细解析!
如果你跟着文章一步步敲了代码,做了练习,那么现在你已经完全掌握了它们的核心内容:
- 你知道了 QTreeWidget 是树形控件,QTreeWidgetItem 是树形节点;
- 你会用 QTreeWidgetItem 的 text、textAlignment、icon、font、hidden、disabled、expanded、sizeHint、selected 这些属性定制节点;
- 你会用 QTreeWidgetItem 的 addChild、childCount、child、takeChild、removeChild、parent 这些方法管理父子节点关系;
- 你会用 QTreeWidget 的 clear、addTopLevelItem、topLevelItem、topLevelItemCount、indexOfTopLevelItem、takeTopLevelItem、currentItem、setCurrentItem、setHeaderLabel 这些方法管理树形控件;
- 你会绑定 currentItemChanged、itemClicked、itemDoubleClicked、itemEntered、itemExpanded、itemCollapsed 这些信号实现交互;
- 你知道了内存管理的规则 (clear 自动释放,takeChild/takeTopLevelItem 要手动 delete)、列号从 0 开始 、itemEntered 要开启鼠标跟踪 、信号触发的区别这些超级重要的注意事项。
毫不夸张地说,掌握了这些内容,你就掌握了 QTreeWidget 开发的 95% 以上的需求!
7.1 核心要点回顾
在结束之前,我们最后再回顾一下这篇文章的核心要点,特别是那些最容易踩坑的地方:
- 所有与列相关的属性和方法,列号都从 0 开始!(超级重要!开篇就讲!);
- 内存管理!(超级重要!说三遍!) :
clear()、addChild()、addTopLevelItem()会自动释放内存!takeChild()、takeTopLevelItem()、removeChild()仅移除节点,必须手动delete!;
- 所有权移交!(超级重要!):子节点添加到父节点、顶层节点添加到树形控件后,所有权移交,父节点 / 树形控件删除时自动释放;
- 重复添加!(超级重要!):同一节点不可重复添加到多个父节点或多次添加为顶层节点;
- 层级限制!(超级重要!) :
childCount()、child()仅操作直接子节点!parent()仅返回直接父节点!topLevelItemCount()、topLevelItem()仅操作顶层节点!
- 判空强制!(超级重要!说三遍!) :
child()、topLevelItem()、currentItem()、parent()获取的指针必须先判空再操作!
- itemEntered 必须先调用 setMouseTracking (true)!(超级重要!);
- 信号触发区别!(超级重要!) :
itemClicked仅用户单击触发,代码选中不触发!currentItemChanged代码选中也触发,重复选中同一条目不触发!
- 笔误纠正!(超级重要!) :
setSizeHints→setSizeHint;itemCollapsend→itemCollapsed;
- QFont 不包含颜色!(超级重要!) :文本颜色需通过
setForeground()单独设置!
7.2 最后的话
编程学习没有捷径,唯手熟尔。QTreeWidget 和 QTreeWidgetItem 的内容虽然不少,但只要你多敲代码、多做练习、多踩坑、多排查,很快就能熟练掌握。
这篇文章虽然很长,但我相信,如果你认真看完了,跟着敲了代码,你一定会对它们有一个极其深刻的理解,再也不会为树形控件开发发愁。
感谢你阅读这篇文章,希望它能帮到你。我们下一篇 Qt 教程再见!