【Qt】多元素控件——QListWidget,QTableWidget,QTreeWidget
目录
一.List Widget
1.1.QListWidgetItem和QListWidget的关系
1.2.QListWidgetItem的核心方法
1.3.核心属性
1.4.核心方法
1.5.核心信号
1.6.示例
二.Table Widget
2.1.QTableWidgetItem和QTableWidget的关系
2.2.QTableWidgetItem核心方法
2.3.核心方法
2.3.1. 获取和设置单元格内容
2.3.2. 处理当前选中项
2.3.3. 通过 Item 反查位置
2.3.4. 获取表格结构信息
2.3.5. 动态修改表格结构
2.3.6. 设置表头
2.4.核心信号
2.5.示例
三.Tree Widget
3.1.QTreeWidgetItem和QTreeWidget的关系
3.2.QTreeWidgetItem核心属性
3.3.QTreeWidgetItem核心方法
3.3.核心方法
3.4.1. 清空操作
3.4.2. 顶层节点操作
3.4.3. 选中操作
3.4.4. 节点展开/关闭
3.4.5. 表头设置
3.5.核心信号
3.6.示例
Qt 中提供的多元素控件有:
- QListWidget
- QListView
- QTableWidget
- QTableView
- QTreeWidget
- QTreeView
xxWidget 与 xxView 的区别
在 UI 开发中,xxView 通常是基于经典 MVC 架构的底层视图组件。
MVC 将软件结构分为三个部分:
-
Model:负责数据存储与业务逻辑
-
View:负责界面呈现与用户交互
-
Controller:负责协调数据与视图之间的业务流程
xxView 仅专注于视图层的实现,不涉及数据管理和业务逻辑控制。这意味着开发者需要自行构建 Model 和 Controller 部分,虽然灵活度高,但也增加了开发复杂度。
相比之下,xxWidget 是在 xxView 基础上的高层封装,已经内置了常用的 Model 和 Controller 逻辑。它提供了一套开箱即用的 API,开发者无需关心底层 MVC 结构的实现细节,能够快速构建功能完整的界面组件,大大提升了开发效率。
以 QTableWidget 和 QTableView 为例
-
QTableView 是典型的基于 MVC 设计的视图组件。它本身不持有数据,使用时需要开发者创建一个 Model 对象(如
QStandardItemModel
),并将其与 QTableView 关联。这种设计中,Model 和 View 之间是双向绑定的:修改 Model 中的数据会自动更新视图,而在视图中编辑内容也会同步到 Model 中。这种结构适合复杂的数据表示和自定义需求。 -
QTableWidget 则是 QTableView 的子类,对其进行了进一步封装。它内置了一个默认的 Model,开发者无需手动创建和管理 Model 对象,可以直接通过简便的 API 添加和操作表格数据。这种设计牺牲了一定的灵活性,但极大简化了基本表格功能的实现,适合快速开发标准表格界面。
总的来说,xxWidget 提供了更高层次的抽象和更便捷的 API,适合常见场景的快速开发;而 xxView 则提供了更底层的控制和灵活性,适合需要自定义数据管理和交互逻辑的复杂场景。
一.List Widget
使⽤ QListWidget 能够显⽰⼀个纵向的列表.
1.1.QListWidgetItem和QListWidget的关系
QListWidget 作为容器控件,而 QListWidgetItem 作为其数据项实体。
这是一种典型的"一对多"聚合关系:
- 一个 QListWidget 实例可以包含零个或多个 QListWidgetItem 实例
- QListWidgetItem 必须依附于某个 QListWidget 才能具有实际的显示意义
我们可以把QListWidget比作一个柜子,把QListWidgetItem比作这个柜子里面的抽屉
QListWidget(柜子)的职责:
-
宏观管理:它掌管着所有
QListWidgetItem
。你可以通过它来addItem
(添加抽屉)、insertItem
(插入抽屉)、takeItem
(拿走但不销毁抽屉)、clear
(清空所有抽屉)。 -
视图设置:它决定列表的显示模式,比如是
ListMode
(单列列表)还是IconMode
(图标模式,类似手机桌面)。 -
信号发射:当用户与整个列表交互时,它来发出信号。最重要的信号是:
-
currentItemChanged
:当前选中的“抽屉”变了。 -
itemClicked
:用户点击了某个“抽屉”。 -
itemDoubleClicked
:用户双击了某个“抽屉”。
你的程序可以通过连接这些信号来触发相应的操作,比如点击一个文件名就打开它。
-
-
选择模式:它控制用户可以选择多少个“抽屉”,是只能选一个,还是可以选多个。
QListWidgetItem(抽屉)的职责:
-
内容存储:它是数据的载体。它最主要的功能是存储和展示:
-
文本 (
setText
):抽屉上的标签文字。 -
图标 (
setIcon
):标签前的小图标。 -
状态 (
setCheckState
):可以变成一个带复选框的抽屉。 -
字体颜色 (
setForeground
,setBackground
):设置文字和背景颜色。 -
自定义控件 (
setSizeHint
,setItemWidget
):你甚至可以把一个按钮、一个进度条塞进这个“抽屉”里!
-
-
状态管理:它知道自己是否被选中(
isSelected
)、是否被勾选(checkState
)、是否是当前项。 -
数据角色:这是高级用法。它可以用
setData
函数存储任何你想存储的“隐藏数据”。比如,一个显示“歌曲名”的抽屉,其背后可以隐藏存储着这首歌的“文件路径”、“歌手”、“时长”等数据。显示时只用文本,但需要播放时,就从隐藏数据里取出路径。
1.2.QListWidgetItem的核心方法
下面,我们来好好讲讲这些核心方法:
1. setText
-
字面意思:设置文本。
-
详细解释: 这是最基础、最常用的方法。它用来设置这个列表项主要显示的文字内容。
-
重要特性:
-
接受一个字符串作为参数。例如
item.setText("张三")
。 -
这是用户一眼看到的主要信息,比如文件名、联系人姓名、歌曲名等。
-
-
使用场景: 几乎每一个列表项都需要用它来设置其核心标识。
2. setIcon
-
字面意思:设置图标。
-
详细解释: 这个方法用于在文本的旁边(通常是左边) 设置一个小的图片或图标。
-
重要特性:
-
它接受一个
QIcon
对象作为参数。QIcon
可以加载各种格式的图片文件(如PNG, SVG)。 -
图标能极大地提升列表的直观性,比如用文件夹图标表示目录,用音乐符号表示歌曲,用用户头像表示联系人。
-
-
使用场景: 当你希望列表项不仅仅通过文字,还能通过视觉符号来快速区分类型或状态时。
3. setFont
-
字面意思:设置字体。
-
详细解释: 这个方法允许你为这个特定的列表项定制文本的字体样式,而不会影响列表中的其他项。
-
重要特性:
-
它接受一个
QFont
对象作为参数。通过QFont
,你可以设置:-
字族:如“微软雅黑”、“Arial”。
-
字号:文字的大小。
-
粗细:如加粗 (
Bold
)、正常 (Normal
)。 -
样式:如斜体 (
Italic
)、下划线 (Underline
)。
-
-
-
使用场景:
-
突出显示:将未读邮件、重要通知的项设置为加粗。
-
状态指示:将已完成的项设置为灰色斜体。
-
个性化:为特定类型的项设置不同的字体。
-
4. setTextAlignment
-
字面意思:设置文本对齐方式。
-
详细解释: 这个方法控制该项的文本内容在其所占用的矩形区域内部如何对齐。
-
重要特性:
-
还记得
QListWidget
有一个全局的itemAlignment
属性吗?setTextAlignment
是针对单个项的、更精细的覆盖。 -
它使用诸如
Qt.AlignLeft
,Qt.AlignRight
,Qt.AlignCenter
等常量。你还可以组合垂直对齐,如Qt.AlignVCenter | Qt.AlignRight
(垂直居中且水平右对齐)。
-
-
使用场景:
-
在一个列表中,让数字金额全部右对齐,方便对比。
-
让某个特殊项居中对齐以引起注意。
-
5. setSizeHint
-
字面意思:设置尺寸提示。
-
详细解释: 这个方法用于向列表“建议”这个项希望拥有多大的尺寸(高度和宽度)。
-
重要特性:
-
它接受一个
QSize
对象,该对象包含宽度和高度。 -
这只是一个“建议”,列表视图在最终布局时可能会综合考虑其他因素,但它通常会尊重这个提示,尤其是在高度上。
-
默认情况下,所有项的高度是统一的。如果你希望某个项特别高或特别矮,就必须使用这个方法。
-
-
使用场景:
-
创建自定义项委托时,你需要告诉列表你的自定义项需要多大空间。
-
实现一个聊天列表,其中某些消息项因为内容多而需要更高的高度。
-
创建一个包含图片预览的列表,需要固定每一项的高度。
-
6. setSelected
-
字面意思:设置选中状态。
-
详细解释: 这个方法允许你以编程方式控制这个项是否处于“被选中”状态。
-
重要特性:
-
它接受一个布尔值:
True
表示选中,False
表示不选中。 -
在单选模式下,如果你将一个项设置为选中,之前选中的项会自动取消选中。
-
在多选模式下,你可以同时将多个项设置为选中状态。
-
这与用户用鼠标点击进行选择的效果是完全一样的。
-
-
使用场景:
-
程序初始化时,自动选中第一项。
-
根据某些逻辑(如搜索过滤后),自动选中符合条件的项。
-
实现“全选”功能。
-
7. setHidden
-
字面意思:设置隐藏。
-
详细解释: 这个方法用于显示或隐藏这个特定的列表项。
-
重要特性:
-
它接受一个布尔值:
True
表示隐藏,False
表示显示。 -
与
setVisible(False)
是等价的。 -
被隐藏的项不会在列表中显示,也不能被用户选中,但它依然存在于列表中,并没有被删除。
-
-
使用场景:
-
实现搜索/过滤:当用户在搜索框输入时,隐藏所有不匹配的项,只显示匹配的项。这是一种非常高效的实时搜索实现方式。
-
临时禁用某些项:在不删除它们的前提下,暂时让用户看不到也接触不到它们。
-
1.3.核心属性
1. currentRow
-
字面意思:当前行。
-
详细解释: 这个属性告诉你,当前被选中的是列表中的第几行。它是一个整数。
-
重要特性:
-
从0开始计数:列表的第一行,
currentRow
的值是0
;第二行是1
,以此类推。 -
-1 的含义:如果没有任何一行被选中(比如列表是空的,或者用户点击了空白区域),
currentRow
的值就是-1
。在编程中,经常需要检查这个值是否为-1
来判断是否有有效选择。 -
通常是单项选择:在默认情况下,
QListWidget
是单选的,所以currentRow
指向的是唯一被选中的那一行。即使你设置为允许多选,currentRow
通常也反映的是最后被用户点击的那一行的索引。
-
-
使用场景: 当你需要知道用户选择了列表中的哪一个项时,就通过这个属性来获取索引,然后根据索引找到对应的项,再进行后续操作(比如显示详细信息、删除、编辑等)。
2. count
-
字面意思:计数。
-
详细解释: 这是一个只读属性,它直接告诉你这个列表总共有多少行(项)。它也是一个整数。
-
重要特性:
-
当你向列表中添加项时,这个值会自动增加;当你删除项时,它会自动减少。
-
你无法直接设置
count = 5
来创建5个空行,必须通过addItem()
等方法实际添加项。
-
-
使用场景: 常用于循环遍历列表中的所有项,或者显示列表的统计信息(如“共找到XX个结果”)。
3. sortingEnabled
-
字面意思:排序启用。
-
详细解释: 这是一个布尔值(True/False)属性,控制列表是否允许自动排序。
-
重要特性:
-
当设置为
True
时,列表会自动按照项的文本内容进行升序排列。之后你每添加一个新的项,它都会自动被插入到正确的位置以保持整体有序。 -
当设置为
False
(默认值)时,项会按照你添加的顺序依次排列在列表的末尾。 -
你也可以在任何时候调用
sortItems()
方法来手动进行一次排序,无论sortingEnabled
是开是关。
-
-
使用场景: 当你希望列表内容始终保持某种顺序(如按文件名、按日期排序)时,启用这个功能会非常方便。
4. isWrapping
-
字面意思:是否换行。
-
详细解释: 这个属性控制当列表的项在横向空间不足时,是否要换行显示。它影响的是视图的布局,而不是单个项文本的换行。
-
重要特性:
-
如果设置为
True
(换行),当列表宽度不足以显示所有列时,它会将多余的项“换行”到下一行,形成一个网格状布局。这通常在图标视图(Icon Mode)下更有用。 -
如果设置为
False
(默认值,不换行),无论列表有多宽,它都只显示一列,并通过垂直滚动条来浏览所有项。这是最经典的列表样式。
-
-
使用场景: 想象一个图片浏览器,你希望缩略图在到达窗口边缘时能自动换到下一行,而不是出现一个很长的纵向列表,这时你就需要启用换行。
5. itemAlignment
-
字面意思:项的对齐方式。
-
详细解释: 这个属性决定了列表中每一个项的内容在它的“格子”里如何水平对齐。
-
重要特性:
-
它的值是诸如
Qt.AlignLeft
(左对齐)、Qt.AlignRight
(右对齐)、Qt.AlignCenter
(居中对齐)、Qt.AlignJustify
(两端对齐)这样的常量。 -
这是全局设置,会对列表中的所有项生效。如果你想对某个特定的项设置不同的对齐方式,需要单独设置那个
QListWidgetItem
的属性。
-
-
使用场景: 数字列表可能希望右对齐,让数字的个十百位对齐;而大部分文本列表则习惯使用左对齐。
6. selectionRectVisible
-
字面意思:选择矩形是否可见。
-
详细解释: 这是一个布尔值属性,控制当用户用鼠标拖拽选择一个区域时,那个半透明的蓝色矩形框是否显示。
-
重要特性:
-
设置为
True
(默认值)时,拖拽选择会显示一个矩形框,清晰地标出选择范围。 -
设置为
False
时,即使你通过拖拽选择了多个项,也不会显示那个矩形框。但是,项本身被选中的状态(如高亮)依然会显示。 -
这个属性主要影响视觉反馈,不影响多选功能本身。
-
-
使用场景: 如果你觉得那个矩形框在特定风格的UI中显得突兀,可以将其隐藏,只依靠项的高亮来指示选中状态。
7. spacing
-
字面意思:间距。
-
详细解释: 这个属性设置列表中相邻项之间的间隔距离,单位是像素。
-
重要特性:
-
默认值通常是
0
,意味着项与项之间是紧挨着的。 -
设置一个正数值(如
5
),会在每个项的周围产生透明的间隔,让列表看起来不那么拥挤。 -
注意它与
margin
(边距,指整个列表Widget边缘的空白)的区别。spacing
是内部项与项之间的间隔。
-
-
使用场景: 为了提升列表的视觉美观度和可读性,避免项与项之间贴得太紧,适当增加间距是一种常见的UI设计技巧。
1.4.核心方法
1. addItem(const QString& label)
功能:在列表末尾添加一个文本项
示例:
QListWidget *listWidget = new QListWidget;// 添加单个项目
listWidget->addItem("苹果");
listWidget->addItem("香蕉");
listWidget->addItem("橙子");// 此时列表显示:
// 苹果
// 香蕉
// 橙子
2. addItem(QListWidgetItem *item)
功能:在列表末尾添加一个 QListWidgetItem 对象(可以包含更多属性),关于这个QListWidgetItem我会在后面进行介绍
示例:
QListWidget *listWidget = new QListWidget;// 创建带有图标的项目
QListWidgetItem *item = new QListWidgetItem;
item->setText("特殊项目");
item->setIcon(QIcon(":/icons/special.png"));
item->setToolTip("这是一个特殊项目");listWidget->addItem(item);
3. currentItem()
功能:返回当前选中的项目指针QListWidgetItem *,如果没有选中则返回 nullptr
示例:
QListWidget *listWidget = new QListWidget;
listWidget->addItems({"项目1", "项目2", "项目3"});// 获取当前选中的项目
QListWidgetItem *current = listWidget->currentItem();if (current) {qDebug() << "当前选中:" << current->text();
} else {qDebug() << "没有选中任何项目";
}// 假设用户点击了"项目2",输出:当前选中: 项目2
4. setCurrentItem(QListWidgetItem* item)
功能:设置指定的项目为选中状态
示例:
QListWidget *listWidget = new QListWidget;
listWidget->addItems({"红色", "绿色", "蓝色"});// 获取第二个项目并设置为选中
QListWidgetItem *secondItem = listWidget->item(1);
listWidget->setCurrentItem(secondItem);// 或者直接通过文本查找
for (int i = 0; i < listWidget->count(); ++i) {if (listWidget->item(i)->text() == "蓝色") {listWidget->setCurrentItem(listWidget->item(i));break;}
}
5. setCurrentRow(int row)
功能:设置指定行的项目为选中状态(行号从0开始)
示例:
QListWidget *listWidget = new QListWidget;
listWidget->addItems({"一月", "二月", "三月", "四月"});// 选中第三行(索引为2)
listWidget->setCurrentRow(2); // 选中"三月"// 选中第一行
listWidget->setCurrentRow(0); // 选中"一月"
6. insertItem(int row, const QString& label)
功能:在指定位置插入文本项目
示例:
QListWidget *listWidget = new QListWidget;
listWidget->addItems({"A", "B", "D"}); // 忘记添加C了// 在索引2的位置插入"C"(在B和D之间)
listWidget->insertItem(2, "C");// 现在列表显示:A, B, C, D// 在开头插入项目
listWidget->insertItem(0, "开始");// 现在列表显示:开始, A, B, C, D
7. insertItem(int row, QListWidgetItem *item)
功能:在指定位置插入 QListWidgetItem 对象
示例:
QListWidget *listWidget = new QListWidget;
listWidget->addItems({"普通项目1", "普通项目2"});// 创建特殊项目并插入到指定位置
QListWidgetItem *specialItem = new QListWidgetItem;
specialItem->setText("特殊插入项目");
specialItem->setBackground(Qt::yellow);// 插入到第一个位置
listWidget->insertItem(1, specialItem);// 列表显示:
// 普通项目1
// 特殊插入项目(黄色背景)
// 普通项目2
8. item(int row)
功能:返回指定行的项目指针
示例:
QListWidget *listWidget = new QListWidget;
listWidget->addItems({"北京", "上海", "广州", "深圳"});// 获取第二行的项目
QListWidgetItem *secondItem = listWidget->item(1);
if (secondItem) {qDebug() << "第二行城市:" << secondItem->text(); // 输出:上海// 可以进一步操作该项目secondItem->setForeground(Qt::red); // 设置为红色文本
}// 获取不存在的行(返回nullptr)
QListWidgetItem *invalidItem = listWidget->item(10);
if (!invalidItem) {qDebug() << "第10行不存在";
}
9. takeItem(int row)
功能:移除并返回指定行的项目(需要手动管理内存)
示例:
QListWidget *listWidget = new QListWidget;
listWidget->addItems({"任务1", "任务2", "任务3", "任务4"});// 移除第二行的项目(索引1)
QListWidgetItem *removedItem = listWidget->takeItem(1);if (removedItem) {qDebug() << "已移除:" << removedItem->text(); // 输出:已移除: 任务2// 重要:需要手动删除取出的项目,否则内存泄漏delete removedItem;
}// 现在列表显示:任务1, 任务3, 任务4// 尝试移除不存在的行
QListWidgetItem *invalidTake = listWidget->takeItem(10);
if (!invalidTake) {qDebug() << "无法移除第10行,不存在";
}
1.5.核心信号
为了让您更好地理解,我们可以将这些信号分为两大类:
-
与“选中状态”变化相关的信号:关注的是项目被“选中”这个状态。
-
与“鼠标动作”相关的信号:关注的是鼠标在项目上的具体操作。
第一类:与“选中状态”变化相关的信号
这类信号的核心是“当前选中的项目发生了变化”。触发方式多种多样,不仅限于鼠标点击。
1. currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
-
字面意思:当前项目改变了。
-
触发时机:每当列表控件中选中的项目发生改变时,就会立即触发。这是最全面的一个选中变化信号。
-
参数详解:
-
*current
:指向当前最新被选中的那个项目的指针。如果现在没有选中的项目(比如列表被清空了),这个参数会是nullptr
。 -
*previous
:指向在这之前被选中的那个项目的指针。如果之前没有选中的项目(比如第一次选中),这个参数会是nullptr
。
-
-
通俗解释:
这个信号像是在汇报:“报告!我们选中的目标已经更换!之前盯着的是A,现在换成了B。” 它把“新宠”和“旧爱”都告诉了你。
-
典型用途:
-
根据当前选中的不同项目,实时更新界面其他部分的内容(例如,选中一个文件名,在旁边显示文件详情)。
-
在选中项改变时,保存前一个项目的状态。
-
2. currentRowChanged(int currentRow)
-
字面意思:当前行改变了。
-
触发时机:与
currentItemChanged
几乎完全相同,也是当选中的项目(行)发生变化时触发。 -
参数详解:
-
currentRow
:当前被选中项目的行号(索引)。行号从0开始计算。如果没有任何选中项,这个值会是 -1。
-
-
通俗解释:
这个信号是
currentItemChanged
的“精简版”。它只汇报:“报告!我们现在选中的是第X号位置!” 它不关心那个位置的项目具体是什么,只关心位置编号。 -
典型用途:
-
当你只关心选中项的位置索引而不是具体内容时,使用这个信号会更方便。例如,用一个行号来操作另一个列表或数组。
-
currentItemChanged
和 currentRowChanged
的重要关系:
它们就像是同一件事情的两种报告方式。当你用鼠标点击一个新项目、用键盘上下键切换选项、或者通过代码设置选中项时,这两个信号会同时被触发。
第二类:与“鼠标动作”相关的信号
这类信号的核心是“用户用鼠标做了什么”。
3. itemClicked(QListWidgetItem *item)
-
字面意思:项目被点击了。
-
触发时机:当用户在某个项目上按下鼠标左键然后释放(完成一次完整的点击) 时触发。
-
参数详解:
-
*item
:指向被点击的那个项目的指针。
-
-
通俗解释:
这个信号说:“注意!用户用鼠标点了一下这个家伙!”
-
一个关键区别:
-
如果你连续点击同一个已经处于选中状态的项目,
itemClicked
信号依然会每次都被触发。 -
而对于
currentItemChanged
,因为选中的项目并没有发生变化(从A到A),所以它不会被触发。
-
-
典型用途:
-
需要响应每次点击动作,即使点击的是当前已选中的项。例如,点击一个已选中的按钮来执行某个命令。
-
4. itemDoubleClicked(QListWidgetItem *item)
-
字面意思:项目被双击了。
-
触发时机:当用户在某个项目上快速连续两次点击鼠标左键时触发。
-
参数详解:
-
*item
:指向被双击的那个项目的指针。
-
-
通俗解释:
这个信号说:“用户在这个项目上快戳了两下!”
-
重要特性:
-
一次双击操作会同时触发一次
itemClicked
和一次itemDoubleClicked
。这是由操作系统的事件机制决定的。
-
-
典型用途:
-
执行“打开”或“编辑”操作。例如,在文件列表中双击一个文件来打开它。
-
5. itemEntered(QListWidgetItem *item)
-
字面意思:鼠标进入了项目区域。
-
触发时机:当鼠标光标移动到一个项目所占的区域内部时触发。
-
参数详解:
-
*item
:指向鼠标进入的那个项目的指针。
-
-
通俗解释:
这个信号说:“看!鼠标光标滑过这个项目了!”
-
一个非常重要的前提条件:
-
这个信号默认是关闭的,为了节省资源。你必须先调用
setMouseTracking(true)
来启用 QListWidget 的鼠标跟踪功能,这个信号才会生效。
-
-
典型用途:
-
实现高级的UI效果,例如鼠标悬停在一个项目上时,该项目改变颜色或显示提示信息。
-
1.6.示例
我们创建一个新项目
它们的objectname如下
我们现在去编写一下代码
注意了哈,我们这里使用了一个信号
currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
-
字面意思:当前项目改变了。
-
触发时机:每当列表控件中选中的项目发生改变时,就会立即触发。这是最全面的一个选中变化信号。
-
参数详解:
-
*current
:指向当前最新被选中的那个项目的指针。如果现在没有选中的项目(比如列表被清空了),这个参数会是nullptr
。 -
*previous
:指向在这之前被选中的那个项目的指针。如果之前没有选中的项目(比如第一次选中),这个参数会是nullptr
。
-
我们运行看看
加入C#看看
我们现在选中C#,进行删除
这个时候我们也可以看到
很好。现在我们先点击C++,他又变成了下面这个
再点击JAVA
咋样?还是非常OK的吧。
二.Table Widget
使⽤ QTableWidget 表⽰⼀个表格控件.⼀个表格中包含若⼲⾏,每⼀⾏⼜包含若⼲列.
表格中的每个单元格,是⼀个 QTableWidgetItem 对象
2.1.QTableWidgetItem和QTableWidget的关系
QTableWidget 作为容器控件,而 QTableWidgetItem 作为其数据项实体。
这是一种典型的"一对多"聚合关系:
-
一个 QTableWidget 实例可以包含零个或多个 QTableWidgetItem 实例
-
QTableWidgetItem 必须依附于某个 QTableWidget 才能具有实际的显示意义
我们可以把QTableWidget比作一个办公桌的桌面,把QTableWidgetItem比作这个桌面上一个个便签纸。
QTableWidget(桌面)的职责:
宏观管理:它掌管着所有 QTableWidgetItem。你可以通过它来设置表格的行列结构,以及通过setItem(row, column, item)
将便签纸放在桌面的特定位置。
视图设置:它决定表格的显示方式,比如:
-
设置表头(
setHorizontalHeaderLabels
设置水平表头标签) -
设置行高列宽(
setRowHeight
,setColumnWidth
) -
设置选择行为(是按行选择还是按单元格选择)
信号发射:当用户与整个表格交互时,它来发出信号。最重要的信号是:
-
cellClicked
:用户点击了某个单元格(便签纸的位置) -
cellDoubleClicked
:用户双击了某个单元格 -
cellChanged
:单元格的内容发生了改变
选择模式:它控制用户可以选择多少个单元格(便签纸),是单选还是多选。
QTableWidgetItem(便签纸)的职责:
内容存储:它是数据的载体。它最主要的功能是存储和展示:
-
文本 (
setText
):便签纸上写的内容 -
图标 (
setIcon
):便签纸上的图标 -
状态 (
setCheckState
):可以变成一个带复选框的便签纸 -
字体颜色 (
setForeground
,setBackground
):设置文字和背景颜色 -
对齐方式 (
setTextAlignment
):设置文本的对齐方式
状态管理:它知道自己是否被选中(isSelected
)、是否被勾选(checkState
)、是否是当前项。
数据角色:这是高级用法。它可以用setData
函数存储任何你想存储的"隐藏数据"。比如,一个显示"员工姓名"的单元格,其背后可以隐藏存储着这个员工的"工号"、"部门"、"入职日期"等数据。显示时只用文本,但需要时,就从隐藏数据里取出工号。
2.2.QTableWidgetItem核心方法
1. int row() const
-
文字讲解:这个方法用于获取当前
QTableWidgetItem
对象在其所属的表格中位于第几行。 -
详细说明:
-
行号的计数是从 0 开始的。也就是说,表格最顶部的第一行是第 0 行,第二行是第 1 行,以此类推。
-
这个方法非常常用,尤其是在处理信号(比如用户点击了一个单元格)时,你需要知道操作发生在哪一行,以便进行后续的数据处理(比如从数据源中删除对应行的数据)。
-
-
注意事项:如果一个
QTableWidgetItem
还没有被插入到表格中,或者已经被移除,它的行号会是 -1。 -
简单示例:
// 假设你有一个单元格点击的槽函数 void onTableItemClicked(QTableWidgetItem *item) {int currentRow = item->row(); // 获取被点击单元格的行号qDebug() << "你点击了第" << currentRow << "行"; }
2. int column() const
-
文字讲解:这个方法用于获取当前
QTableWidgetItem
对象在其所属的表格中位于第几列。 -
详细说明:
-
和
row()
方法一样,列号的计数也是从 0 开始的。最左边的第一列是第 0 列,第二列是第 1 列。 -
通常,
row()
和column()
会一起使用,来精确定位一个单元格在表格中的位置 (row, column)。
-
-
简单示例:
void onTableItemClicked(QTableWidgetItem *item) {int currentRow = item->row();int currentColumn = item->column();qDebug() << "你点击的单元格位置是: (" << currentRow << ", " << currentColumn << ")"; }
3. void setText(const QString &text)
-
文字讲解:这是最常用的方法之一,用于设置单元格中显示的主要文本内容。
-
详细说明:
-
它接受一个
QString
类型的参数,也就是你想要在单元格里显示的文字。 -
这个方法决定了用户在表格上直观看到的内容。
-
-
简单示例:
// 创建一个新的表格项 QTableWidgetItem *nameItem = new QTableWidgetItem(); // 设置其显示文本为 "张三" nameItem->setText("张三");// 也可以直接在创建时设置文本 QTableWidgetItem *ageItem = new QTableWidgetItem("25");// 将这个项设置到表格的第0行第0列 tableWidget->setItem(0, 0, nameItem);
4. void setTextAlignment(int alignment)
-
文字讲解:这个方法用于设置单元格内文本的对齐方式。
-
详细说明:
-
它让文本的显示更加美观和规范。比如,数字通常右对齐,文本通常左对齐,标题可以居中对齐。
-
参数
alignment
是 Qt 中定义的一些枚举常量,常用有以下几种:-
Qt::AlignLeft
:左对齐 -
Qt::AlignRight
:右对齐 -
Qt::AlignHCenter
:水平居中 -
Qt::AlignTop
:顶部对齐 -
Qt::AlignBottom
:底部对齐 -
Qt::AlignVCenter
:垂直居中 -
你也可以使用
|
运算符组合,比如Qt::AlignVCenter | Qt::AlignRight
表示垂直居中且水平右对齐。
-
-
-
简单示例:
QTableWidgetItem *item = new QTableWidgetItem("100"); // 设置文本为水平方向右对齐,垂直方向居中对齐 item->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
5. void setIcon(const QIcon &icon)
-
文字讲解:这个方法用于在单元格的文本旁边设置一个图标。
-
详细说明:
-
它可以用于可视化地表示一些状态。例如,用一个勾选(✔)图标表示“完成”,用一个警告(⚠)图标表示“错误”,用用户头像表示一个人。
-
参数是一个
QIcon
对象,你可以从图片文件(如PNG, SVG)或者 Qt 的内置图标库来创建它。
-
-
简单示例:
QTableWidgetItem *statusItem = new QTableWidgetItem("完成"); // 从一个图片文件创建图标 QIcon okIcon(":/images/ok.png"); // 设置图标 statusItem->setIcon(okIcon);
6. void setSelected(bool select)
-
文字讲解:这个方法用于以编程方式设置该单元格的选中状态。
-
详细说明:
-
当参数
select
为true
时,单元格会呈现被选中的状态(通常是高亮的蓝色背景)。 -
当参数为
false
时,则取消选中状态。 -
这个方法通常用于你需要在代码中控制选中哪个单元格,而不是由用户去点击。例如,在表格中搜索到某个结果后,自动选中该行。
-
-
注意事项:要确保这个 item 已经被添加到表格中(即
tableWidget->setItem(...)
),否则设置无效。 -
简单示例:
// 获取第2行第1列的单元格项 QTableWidgetItem *item = tableWidget->item(2, 1); if (item) {// 设置为选中状态item->setSelected(true); }
7. void setSizeHint(const QSize &size)
-
文字讲解:这个方法用于给单元格建议一个尺寸(宽度和高度)。
-
详细说明:
-
表格在布局时,行高和列宽会根据内容自动调整。但如果你希望某个单元格(或某行/某列)有特定的大小,可以使用这个方法给它一个“建议尺寸”。
-
参数
size
是一个QSize
对象,它包含了建议的宽度(width)和高度(height)。 -
注意,这只是一个“建议”(Hint),表格的最终布局可能会因为其他设置(如拉伸模式、用户手动调整)而忽略这个建议。
-
-
简单示例:
QTableWidgetItem *item = new QTableWidgetItem("一些很长的内容..."); // 建议这个单元格的高度为40像素,宽度为150像素 item->setSizeHint(QSize(150, 40));
8. void setFont(const QFont &font)
-
文字讲解:这个方法用于设置单元格文本的字体。
-
详细说明:
-
它可以改变文本的字样、大小、粗细、斜体等属性。
-
参数是一个
QFont
对象。你可以创建一个新的QFont
,并设置其属性。 -
常用于突出显示某些重要的单元格,比如将标题加粗,或者将错误信息显示为红色斜体。
-
-
简单示例:
QTableWidgetItem *headerItem = new QTableWidgetItem("姓名"); // 创建一个字体对象 QFont font; font.setBold(true); // 设置为粗体 font.setPointSize(12); // 设置字号为12 // 应用字体 headerItem->setFont(font);
2.3.核心方法
首先,把 QTableWidget
想象成一个 Excel 表格。它有行、有列,行和列交叉形成的一个个小格子叫单元格。每个单元格里可以存放一个 QTableWidgetItem
(你可以把它理解为表格中的“内容块”,可以显示文字、图标等)。
我们将方法分为几类来讲解:
2.3.1. 获取和设置单元格内容
item(int row, int column)
-
说明:根据指定的行号(
row
)和列号(column
),获取该位置上的QTableWidgetItem
对象。 -
深入讲解:
-
这是最核心的获取内容的方法。如果你想读取或修改某个单元格里的文字,你必须先通过这个方法拿到对应的
item
。 -
索引从0开始:第0行,第0列是表格的左上角第一个单元格。
-
重要:如果那个位置是空的(没有被
setItem
设置过),这个方法会返回nullptr
(空指针)。所以,在操作返回的item
之前,一定要判断是否为空,否则程序可能会崩溃。
-
-
示例:
tableWidget->item(0, 0)
获取第1行第1列的 item。
setItem(int row, int column, QTableWidgetItem* item)
-
说明:在指定的行(
row
)和列(column
)位置,设置一个QTableWidgetItem
对象。 -
深入讲解:
-
这是最核心的设置内容的方法。你需要先创建一个
QTableWidgetItem
,然后用这个方法把它“放”到表格的指定位置。 -
这个方法会“接管”你传入的
item
对象的内存管理,你一般不需要手动删除它。 -
如果那个位置已经有 item 了,新的 item 会覆盖旧的。
-
-
示例:
// 创建一个显示 "Hello" 的 item QTableWidgetItem *newItem = new QTableWidgetItem("Hello"); // 将它放到第2行第3列 (注意索引) tableWidget->setItem(1, 2, newItem);
2.3.2. 处理当前选中项
这一组方法通常一起使用,用于响应用户点击单元格的操作。
currentItem()
-
说明:返回当前被选中的单元格对应的
QTableWidgetItem*
。 -
深入讲解:
-
“当前选中”通常是指有焦点高亮的那个单元格。
-
同样,如果没有选中的项,这个函数返回
nullptr
。使用前务必检查。
-
currentRow()
-
说明:返回当前被选中单元格的行索引。
-
深入讲解:
-
这是一个非常方便的方法。你不需要先拿到
item
再问它是第几行,直接调用这个函数即可。 -
如果没有选中的项,这个函数返回 -1。
-
currentColumn()
-
说明:返回当前被选中单元格的列索引。
-
深入讲解:
-
和
currentRow()
一样方便,直接获取列号。 -
如果没有选中的项,返回 -1。
-
使用场景:当用户点击表格某一行,你希望获取这一整行的数据时:
int current_row = tableWidget->currentRow();
if (current_row != -1) { // 确保有选中的行// 然后就可以用 item(current_row, 0), item(current_row, 1)... 来获取该行各列的数据QString name = tableWidget->item(current_row, 0)->text();// ...
}
2.3.3. 通过 Item 反查位置
row(QTableWidgetItem* item)
-
说明:给你一个
item
指针,它告诉你这个 item 位于表格的第几行。 -
深入讲解:
-
当你已经有一个
item
对象(比如通过item()
函数获取的,或者是信号传递过来的),但想知道它的位置时,就用这个方法。 -
如果传入的
item
是nullptr
或者不属于这个表格,返回 -1。
-
column(QTableWidgetItem* item)
-
说明:给你一个
item
指针,它告诉你这个 item 位于表格的第几列。 -
深入讲解:同上。
使用场景:比如你连接了 cellChanged(int row, int col)
信号,但在槽函数中你更习惯通过 item 来操作,然后想再知道它的位置:
void MyClass::onCellChanged(QTableWidgetItem *changedItem) {int r = tableWidget->row(changedItem);int c = tableWidget->column(changedItem);qDebug() << "单元格" << r << c << "被修改了,新内容是:" << changedItem->text();
}
2.3.4. 获取表格结构信息
rowCount()
-
说明:返回表格当前的总行数。
-
深入讲解:常用于循环遍历所有行。
for (int i = 0; i < tableWidget->rowCount(); ++i) {// 处理第 i 行 }
columnCount()
-
说明:返回表格当前的总列数。
-
深入讲解:常用于循环遍历所有列,或者在初始化表格时设置固定的列数。
2.3.5. 动态修改表格结构
insertRow(int row)
-
说明:在指定的行索引
row
处,插入一个新行。原来在这一行及之后的所有行会向下移动。 -
深入讲解:
-
insertRow(0)
在开头插入一行。 -
insertRow(rowCount())
在最后追加一行(这是最常用的操作之一)。 -
插入的新行所有单元格都是空的。
-
insertColumn(int column)
-
说明:在指定的列索引
column
处,插入一个新列。原来在这一列及之后的所有列会向右移动。 -
深入讲解:用法同
insertRow
。
removeRow(int row)
-
说明:删除指定行索引
row
的那一行。后面的行会向上移动。 -
深入讲解:
-
删除行时会自动销毁该行所有的
QTableWidgetItem
。 -
注意索引:如果你在循环中删除多行,应该从后往前删(例如
for (int i = rowCount()-1; i >=0; --i)
),因为从前往后删会导致行索引发生变化。
-
removeColumn(int column)
-
说明:删除指定列索引
column
的那一列。后面的列会向左移动。 -
深入讲解:注意事项同
removeRow
。
2.3.6. 设置表头
setHorizontalHeaderItem(int column, QTableWidgetItem* item)
-
说明:设置水平表头(就是顶部的 A, B, C... 列标题)某一列的表头项。
-
深入讲解:
-
你需要专门为表头创建一个
QTableWidgetItem
,比如new QTableWidgetItem("姓名")
,然后用这个方法把它设置为第column
列的标题。 -
通常会在初始化表格时调用。
-
setVerticalHeaderItem(int row, QTableWidgetItem* item)
-
说明:设置垂直表头(就是左边的 1, 2, 3... 行标题)某一行的表头项。
-
深入讲解:用法同水平表头。如果你不需要显示行号,可以隐藏垂直表头。
更常用的设置表头方法:
虽然上面两个方法很灵活,但更常见的做法是直接用字符串列表一次性设置所有表头:
// 设置水平表头
QStringList horizontalHeaders;
horizontalHeaders << "ID" << "Name" << "Age";
tableWidget->setHorizontalHeaderLabels(horizontalHeaders);// 设置垂直表头(不常用)
// QStringList verticalHeaders;
// verticalHeaders << "Row1" << "Row2";
// tableWidget->setVerticalHeaderLabels(verticalHeaders);
2.4.核心信号
首先,请注意一个关键点:这些信号是属于 QTableWidget 本身的,而不是 QTableWidgetItem。
QTableWidgetItem 代表的是表格中的每一个单元格项目,它本身不发出这些关于用户交互(如点击、进入)的信号,这些信号是由容纳它们的表格控件 QTableWidget 发出的。
下面我们逐一进行讲解:
1. cellClicked(int row, int column)
-
字面意思:单元格被点击。
-
触发时机:当用户在表格的某一个单元格上按下鼠标按键然后释放时,这个信号就会被触发。这是一个完整的“点击”动作。
-
传递的参数:
-
row
:被点击单元格所在的行号(从0开始计数)。 -
column
:被点击单元格所在的列号(从0开始计数)。
-
-
详细说明与典型应用场景:
-
这是最常用、最基础的单元格交互信号。
-
它通常用于获取单元格内容或执行一个主要操作。例如,你点击表格中的某一行,程序右侧的详细信息区域就会更新显示这一行对应的完整信息。
-
它与
currentCellChanged
的区别在于:cellClicked
必须由鼠标点击触发。如果你使用键盘的上下左右键来切换当前选中的单元格,cellClicked
是不会被触发的。 -
示例:一个联系人列表,点击某一行,下方就显示该联系人的电话、邮箱等详细信息。
-
2. cellDoubleClicked(int row, int column)
-
字面意思:单元格被双击。
-
触发时机:当用户在一个单元格上快速连续地按下并释放鼠标按键两次时触发。
-
传递的参数:
-
row
:被双击单元格所在的行号。 -
column
:被双击单元格所在的列号。
-
-
详细说明与典型应用场景:
-
这个信号通常用于执行一个“打开”或“编辑”的深层操作。
-
在软件设计中,有一个常见的交互模式:单击选择,双击打开。例如,在文件管理器中,单击一个文件是选中它,双击一个文件则是打开它。
-
重要提示:当你双击一个单元格时,会先触发一次
cellClicked
信号,然后再触发cellDoubleClicked
信号。在设计逻辑时需要注意,避免冲突。 -
示例:双击表格中的一行,弹出一个新的对话框来编辑这一行的所有数据。
-
3. cellEntered(int row, int column)
-
字面意思:鼠标进入了单元格的区域。
-
触发时机:当鼠标光标移动进入一个单元格的区域时触发。
-
传递的参数:
-
row
:鼠标进入的单元格的行号。 -
column
:鼠标进入的单元格的列号。
-
-
详细说明与典型应用场景:
-
这个信号关注的是鼠标的悬停,而不是点击。
-
它的触发频率非常高,只要鼠标在表格上移动,经过每一个单元格都会触发一次。
-
典型用途是实现鼠标悬停提示(ToolTip) 或高亮显示鼠标所在行。
-
注意:默认情况下,这个信号可能不会被触发,需要将
QTableWidget
的mouseTracking
属性设置为True
才会生效。 -
示例:当鼠标在股票代码列表上移动时,在鼠标旁边实时显示该股票的更详细摘要信息。
-
4. currentCellChanged(int currentRow, int currentColumn, int previousRow, int previousColumn)
-
字面意思:当前选中的单元格发生了改变。
-
触发时机:当表格中“当前被选中的”单元格发生变化时触发。这个变化可以由鼠标点击或键盘导航(如Tab键、方向键) 引起。
-
传递的参数:
-
currentRow
:新的当前单元格的行号。如果没有当前单元格(例如表格清空),此值为-1。 -
currentColumn
:新的当前单元格的列号。 -
previousRow
:之前的当前单元格的行号。如果之前没有选中,此值为-1。 -
previousColumn
:之前的当前单元格的列号。
-
-
详细说明与典型应用场景:
-
这是功能最强大、信息最全面的选中变化信号。
-
它不仅告诉了你现在选的是谁 (
currentRow
,currentColumn
),还告诉了你之前选的是谁 (previousRow
,previousColumn
)。这在某些需要做状态清理或保存的场景下非常有用。 -
它与
cellClicked
的关键区别在于:currentCellChanged
对键盘和鼠标操作都响应。只要你切换了选中项,它就会触发。 -
示例:
-
在一个数据录入表格中,当用户从一个单元格切换到另一个时,自动验证并保存前一个单元格刚输入的内容。
-
跟踪用户的选择轨迹。
-
-
2.5.示例
我们创建一个新项目
它们的objectname如下
我们写一下代码
运行一下
怎么样?这个表格是不是很好看啊。现在我们还需要给4个按钮配置槽函数
怎么配置槽函数我就不讲了啊,我们直接看代码
我们运行一下
我们发现表格最末尾增加了一行
接下来我们来测试一下删除选中行的按钮
很完美,接下来来测序新增一列的按钮
很好,我们现在就来删除选中行
很完美啊。
注意:默认情况下,单元格中的内容直接就是可编辑的.
如果不想让⽤⼾编辑,可以设置
ui->tableWidget >setEditTriggers(QAbstractItemView::NoEditTriggers);
三.Tree Widget
使⽤ QTreeWidget 表⽰⼀个树形控件.⾥⾯的每个元素,都是⼀个 QTreeWidgetItem ,每个 QTreeWidgetItem 可以包含多个⽂本和图标,每个⽂本/图标为⼀个列.
可以给 QTreeWidget 设置顶层节点(顶层节点可以有多个),然后再给顶层节点添加⼦节点,从⽽构成 树形结构.
3.1.QTreeWidgetItem和QTreeWidget的关系
QTreeWidget
作为容器控件,而 QTreeWidgetItem
作为其数据项实体。
这是一种典型的"一对多"的层次化聚合关系:
-
一个
QTreeWidget
实例可以包含零个或多个QTreeWidgetItem
实例作为顶级节点 -
每个
QTreeWidgetItem
又可以包含零个或多个QTreeWidgetItem
作为其子节点 -
QTreeWidgetItem
必须依附于某个QTreeWidget
(或作为其他QTreeWidgetItem
的子节点)才能具有实际的显示意义
我们可以把 QTreeWidget
比作一个公司组织架构,把 QTreeWidgetItem
比作这个公司里的部门或员工。
QTreeWidget(公司)的职责:
宏观管理:它掌管着所有节点(包括顶级节点和子节点)。你可以通过它来:
-
addTopLevelItem
(添加顶级部门) -
insertTopLevelItem
(插入顶级部门) -
takeTopLevelItem
(拿走但不销毁顶级部门) -
clear
(清空所有部门)
视图设置:它决定树的显示模式,比如:
-
列数设置 (
setColumnCount
) -
表头标签 (
setHeaderLabels
) -
展开/折叠行为
信号发射:当用户与整个树交互时,它来发出信号。最重要的信号是:
-
currentItemChanged
:当前选中的"部门或员工"变了 -
itemClicked
:用户点击了某个"部门或员工" -
itemDoubleClicked
:用户双击了某个"部门或员工" -
itemExpanded
:部门被展开 -
itemCollapsed
:部门被折叠
选择模式:它控制用户可以选择多少个"部门或员工",是只能选一个,还是可以选多个。
QTreeWidgetItem(部门或员工)的职责:
内容存储:它是数据的载体。它最主要的功能是存储和展示:
-
文本 (
setText
):在各列上显示的标签文字 -
图标 (
setIcon
):标签前的小图标 -
状态 (
setCheckState
):可以变成一个带复选框的节点 -
字体颜色 (
setForeground
,setBackground
):设置文字和背景颜色 -
自定义控件 (
setSizeHint
):你甚至可以把一个按钮、一个进度条塞进这个"部门"里!
层次关系管理:
-
addChild
:添加子部门或员工 -
insertChild
:插入子部门或员工 -
takeChild
:移除子部门或员工 -
childCount
:查看有多少下属 -
parent
:查看上级部门
状态管理:它知道自己是否被选中(isSelected
)、是否被勾选(checkState
)、是否是当前项、是否展开等。
数据角色:这是高级用法。它可以用 setData
函数存储任何你想存储的"隐藏数据"。比如,一个显示"部门名称"的节点,其背后可以隐藏存储着该部门的"预算"、"负责人"、"成立日期"等数据。显示时只用文本,但需要处理时,就从隐藏数据里取出相关信息。
3.2.QTreeWidgetItem核心属性
QTreeWidgetItem
是 Qt 中用来在树形视图(QTreeWidget
)中表示一个“项”的类。你可以把它想象成 Windows 资源管理器左侧文件夹树中的一个节点,或者一个组织架构图中的一个职员框。每个项都可以有父项和子项,从而形成层级结构。
下面我们逐一剖析这些属性:
1. text(持有的文本)
-
是什么:这是项最基本、最常用的属性,即显示在界面上的文字。
-
深入讲解:
-
一个
QTreeWidgetItem
可以有多列(就像表格一样)。因此,text
属性实际上是一个列表,对应每一列显示的文本。 -
你通过
setText(column, text)
来设置特定列的文字,通过text(column)
来获取。 -
第 0 列 通常是主列,当项有父子关系时,父子关系就体现在第 0 列上。
-
-
示例:
-
在一个表示文件的树中,第 0 列可能是“文件名”,第 1 列可能是“大小”,第 2 列可能是“修改日期”。
-
item.setText(0, “我的文档”)
-> 在第一列显示“我的文档”。 -
item.setText(1, “1.2 MB”)
-> 在第二列显示“1.2 MB”。
-
2. textAlignment(文本对齐方式)
-
是什么:控制项中每一列文本在单元格内的水平对齐方式。
-
深入讲解:
-
和
text
一样,它也是按列设置的。 -
使用 Qt 的对齐标志(Alignment Flag)来设置,例如:
-
Qt.AlignLeft
:左对齐(默认) -
Qt.AlignRight
:右对齐(非常适合显示数字,如文件大小) -
Qt.AlignCenter
:居中对齐(适合显示状态) -
Qt.AlignHCenter
:水平居中
-
-
合理使用对齐方式可以让数据看起来更整齐、专业。
-
-
示例:
-
item.setTextAlignment(1, Qt.AlignRight | Qt.AlignVCenter)
-> 将第二列的文本设置为右对齐、垂直居中。
-
3. icon(持有的图标)
-
是什么:显示在文本旁边的图标,用于直观地表示项的类型或状态。
-
深入讲解:
-
同样,图标也是按列设置的,但通常我们只在第 0 列(主列)设置图标。
-
你需要提供一个
QIcon
对象,它可以来自资源文件(.qrc
)、磁盘上的图片文件或者 Qt 的内置图标。 -
图标能极大地提升用户体验,让用户快速识别项的功能(如文件夹图标、文档图标、警告图标等)。
-
-
示例:
-
item.setIcon(0, QIcon(“:/images/folder.png”))
-> 在第 0 列文本前显示一个文件夹图标。
-
4. font(文本字体)
-
是什么:控制项文本的字体样式,如粗体、斜体、大小、字体家族等。
-
深入讲解:
-
通过
setFont(column, QFont)
来设置特定列的字体。 -
你可以创建一个
QFont
对象,设置其属性,然后应用到项上。 -
常用于突出显示某些重要的项。例如,未读消息用粗体,过期任务用斜体等。
-
5. hidden(是否隐藏)
-
是什么:一个布尔值,控制整个项(包括所有列)在树形视图中是显示还是隐藏。
-
深入讲解:
-
setHidden(True)
会隐藏该项及其所有子项。 -
它只是视觉上的隐藏,项仍然存在,你可以通过代码对其进行操作。
-
常用于实现过滤功能。例如,在一个搜索框中输入关键词,将所有不匹配的项隐藏起来。
-
与
setExpanded(False)
的区别:后者只是折叠子项,该项本身依然可见;而前者是整个项都不可见。
-
6. disabled(是否禁用)
-
是什么:一个布尔值,控制项是否被禁用(灰显)。
-
深入讲解:
-
setDisabled(True)
会使该项变为灰色,并且用户无法通过鼠标或键盘与之交互(如选择、展开/折叠)。 -
它表示该选项在当前上下文下是“不可用”的。这符合常见的设计规范,比直接隐藏更能向用户传达“功能存在但条件不满足”的信息。
-
例如,在某些操作未完成前,禁用相关的配置项。
-
7. expanded(是否展开)
-
是什么:一个布尔值,控制该项如果是父项,其子项列表是展开(可见)还是折叠(不可见)的状态。
-
深入讲解:
-
只对拥有子项的项有意义。
-
setExpanded(True)
会展开该项,显示其所有子项。 -
setExpanded(False)
会折叠该项,隐藏其所有子项。 -
常用于初始化界面时恢复用户的布局,或者在程序逻辑中自动展开到某一层级。
-
8. sizeHint(尺寸大小)
-
是什么:为项建议一个尺寸(
QSize
),告诉布局系统这个项希望有多大。 -
深入讲解:
-
这是一个高级属性,在大多数情况下你不需要手动设置,Qt 会根据自己的样式和内容自动计算一个合适的尺寸。
-
当你需要项比默认更大或更小时(例如,项内要显示一个特别大的图标,或者多行文本),才会用到它。
-
设置
sizeHint
只是“建议”,布局管理器最终可能会根据实际情况进行调整。
-
9. selected(是否选中)
-
是什么:一个布尔值,表示该项是否被用户选中。
-
深入讲解:
-
这是一个只读属性。你通常不应该直接使用
setSelected()
(虽然理论上可以,但不推荐),因为这会破坏QTreeWidget
内置的选区管理。 -
正确的操作方式是使用
QTreeWidget
的选区相关方法,如setCurrentItem()
。 -
你更多的是在代码中读取这个属性,来判断用户当前选中了哪个项,以便执行相应的操作。
-
项的被选中状态会伴随着视觉上的高亮显示。
-
3.3.QTreeWidgetItem核心方法
1. addChild(QTreeWidgetItem* child)
-
功能说明:这是最常用的方法之一,它的作用是为当前项(调用这个方法的 item)新增一个子节点。你可以把它想象成给一个文件夹(父节点)里面添加一个新的文件或子文件夹(子节点)。
-
参数:它接受一个
QTreeWidgetItem*
类型的参数,也就是一个已经创建好的树形项对象。这个对象就是你想要添加的子节点。 -
重要特性:
-
建立父子关系:调用此方法后,
child
项会正式成为当前项的子项。同时,child
项的parent()
方法将返回当前项。 -
自动显示:当你把子项添加到父项后,Qt的视图组件(
QTreeWidget
)会自动刷新显示,你无需手动刷新界面。
-
-
代码示例:
// 假设我们有一个根节点 rootItem QTreeWidgetItem *rootItem = new QTreeWidgetItem(); rootItem->setText(0, "根目录"); // 设置第一列的显示文本// 创建一个子节点 QTreeWidgetItem *childItem = new QTreeWidgetItem(); childItem->setText(0, "子文件");// 关键一步:将 childItem 添加为 rootItem 的子节点 rootItem->addChild(childItem);
执行后,在界面上你会看到“根目录”前面有一个可展开的箭头,点开它就能看到“子文件”。
2. childCount()
-
功能说明:这个方法返回当前项所拥有的直接子节点的总数量。它只统计“儿子”,不统计“孙子”。它非常常用于遍历一个节点的所有子节点。
-
返回值:一个整数(
int
),表示子节点的个数。如果当前项没有任何子节点,则返回0。 -
使用场景:当你需要遍历一个节点的所有子节点进行处理(如查找、修改、删除)时,你首先需要通过
childCount()
知道循环的范围。 -
代码示例:
// 接上例,现在我们想遍历 rootItem 的所有子节点 int count = rootItem->childCount(); // 此时 count 应该是 1for (int i = 0; i < rootItem->childCount(); ++i) {QTreeWidgetItem *aChild = rootItem->child(i); // 通过下标获取子节点qDebug() << "子节点文本:" << aChild->text(0); }
3. child(int index)
-
功能说明:根据给定的下标(索引),获取当前项的某一个直接子节点。下标从0开始,就像数组一样。
-
参数:一个整数
index
,表示你想要获取的第几个子节点(0代表第一个,1代表第二个,以此类推)。 -
返回值:一个指向
QTreeWidgetItem
的指针。如果提供的index
无效(比如小于0或大于等于childCount()
),则返回nullptr
。 -
与
parent()
的关系:child()
是从父节点找子节点,而parent()
是从子节点找父节点。它们是互逆的操作。
4. takeChild(int index)
-
功能说明:从当前项中移除指定下标处的子节点,并返回这个被移除的子节点。
-
关键点:
-
“拿走”而非“销毁”:这个方法只是解除了父子关系,并将子节点的指针返回给你。这个被移除的节点对象依然存在于内存中。
-
所有权转移:在移除之前,该子节点由其父节点管理。移除后,这个节点的所有权就转移到了你的代码中。你有责任决定是继续使用它、将它添加到别处,还是删除它以防止内存泄漏。
-
界面更新:调用后,界面会立即更新,该子项从树中消失。
-
-
使用场景:当你需要将一个节点从一个父节点移动到另一个父节点时,或者想在删除前对节点进行一些操作时,这个方法非常有用。
-
代码示例:
// 从 rootItem 中“拿走”第一个子节点 QTreeWidgetItem *removedChild = rootItem->takeChild(0);if (removedChild) {// 现在 removedChild 已经不在树中了,但对象还在// 我们可以把它加到别的地方,或者...// ...直接删除它delete removedChild; }
5. removeChild(QTreeWidgetItem* child)
-
功能说明:从当前项中移除并删除指定的子节点。
-
关键点:
-
“销毁”:这个方法不仅移除了子节点,还直接调用
delete
销毁了该子节点对象。之后你再访问这个child
指针就是危险的(悬空指针)。 -
一步到位:如果你确定这个子节点不再需要,用这个方法最方便,因为它自动帮你清理了内存。
-
-
与
takeChild()
的区别:这是最重要的区别。-
takeChild(index)
:只解除关系,不删除。你负责管理内存。 -
removeChild(child)
:解除关系并直接删除。你不再需要管理内存。
-
-
代码示例:
// 创建一个子节点并添加 QTreeWidgetItem *tempChild = new QTreeWidgetItem(); tempChild->setText(0, "临时文件"); rootItem->addChild(tempChild);// 现在我们要直接移除并删除它 rootItem->removeChild(tempChild); // 此后,tempChild 指针不再有效
6. parent()
-
功能说明:获取当前项的父节点。
-
返回值:一个指向
QTreeWidgetItem
的指针。如果当前项是顶层项(没有父节点,直接挂在QTreeWidget
上),则返回nullptr
。 -
使用场景:当你有一个子节点,需要向上查找它的父节点、祖父节点,或者判断它处于树的哪一层时,这个方法就派上用场了。
-
代码示例:
// 假设我们现在有一个子节点 childItem QTreeWidgetItem *parentItem = childItem->parent();if (parentItem) {// 如果 parentItem 不是 nullptr,说明 childItem 有父节点qDebug() << "我的父节点是:" << parentItem->text(0); } else {qDebug() << "我是一个顶层节点!"; }
3.3.核心方法
把 QTreeWidget
想象成 Windows 的资源管理器左侧的文件夹树状结构:
-
顶层节点:就像 C盘、D盘 这样的根目录
-
子节点:就像文件夹里面的子文件夹
-
QTreeWidgetItem:树中的每一个节点(无论是顶层还是子节点)
方法详解
3.4.1. 清空操作
clear()
-
说明:清空树形控件中的所有节点,包括所有顶层节点和它们的子节点。
-
深入讲解:
-
这是一个彻底清理的方法,调用后整个树就变成空的了。
-
它会自动删除所有节点的内存,所以你不需要手动删除每个节点。
-
使用场景:当需要重新加载数据,或者重置整个树结构时使用。
-
3.4.2. 顶层节点操作
这一组方法专门处理树的最顶层节点。
addTopLevelItem(QTreeWidgetItem* item)
-
说明:在树形控件中添加一个顶层节点。
-
深入讲解:
-
顶层节点是树的最外层节点,没有父节点。
-
你可以添加多个顶层节点,它们会按添加顺序依次显示。
-
示例:在文件管理器中,"C盘"、"D盘"就是顶层节点。
QTreeWidgetItem *topItem = new QTreeWidgetItem(); topItem->setText(0, "我的电脑"); treeWidget->addTopLevelItem(topItem);
-
topLevelItem(int index)
-
说明:根据索引获取指定的顶层节点。
-
深入讲解:
-
索引从 0 开始,
topLevelItem(0)
获取第一个顶层节点。 -
如果索引超出范围,返回
nullptr
。
-
topLevelItemCount()
-
说明:获取顶层节点的总数量。
-
深入讲解:
-
常用于循环遍历所有顶层节点。
for (int i = 0; i < treeWidget->topLevelItemCount(); ++i) {QTreeWidgetItem *topItem = treeWidget->topLevelItem(i);// 处理每个顶层节点 }
-
indexOfTopLevelItem(QTreeWidgetItem* item)
-
说明:查询指定节点在顶层节点中的位置索引。
-
深入讲解:
-
如果你有一个节点指针,想知道它是第几个顶层节点,就用这个方法。
-
如果该节点不是顶层节点,返回 -1。
-
takeTopLevelItem(int index)
-
说明:移除指定索引的顶层节点,并返回被移除的节点。
-
深入讲解:
-
注意:这只是移除,不是删除。节点还在内存中,只是从树上拿下来了。
-
你需要自己管理返回的节点的内存,否则会造成内存泄漏。
-
使用场景:当你想要把节点从一个位置移动到另一个位置时。
// 移除第一个顶层节点,但不删除它 QTreeWidgetItem *removedItem = treeWidget->takeTopLevelItem(0); // 可以把它作为其他节点的子节点,或者手动删除
-
3.4.3. 选中操作
currentItem()
-
说明:获取当前被选中的节点。
-
深入讲解:
-
这是最常用的方法之一,用于响应用户的选择操作。
-
如果没有选中的节点,返回
nullptr
。 -
使用场景:当用户点击树节点时,获取该节点并执行相应操作。
-
setCurrentItem(QTreeWidgetItem* item)
-
说明:编程方式选中指定的节点。
-
深入讲解:
-
通过代码来选中某个节点,视觉效果和用户点击选中一样。
-
这会触发相应的选择改变信号。
-
使用场景:程序初始化时默认选中某个节点,或者根据某些条件自动选中节点。
-
3.4.4. 节点展开/关闭
setExpanded(bool)
-
说明:设置节点是否展开(显示子节点)或关闭(隐藏子节点)。
-
深入讲解:
-
注意:这是
QTreeWidgetItem
的方法,不是QTreeWidget
的。 -
true
= 展开,false
= 关闭。 -
使用场景:
QTreeWidgetItem *item = treeWidget->currentItem(); if (item) {item->setExpanded(true); // 展开当前选中的节点 }
-
3.4.5. 表头设置
setHeaderLabel(const QString& text)
-
说明:设置树形控件的表头标题。
-
深入讲解:
-
树形控件通常只有一列,所以这个方法设置的就是这一列的标题。
-
如果你需要多列,应该使用
setHeaderLabels()
方法。 -
示例:
treeWidget->setHeaderLabel("文件目录");
-
3.5.核心信号
1.currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
-
字面意思:当前项目改变。
-
触发时机:当树形部件中具有“焦点”的选中项发生改变时触发。
-
深入讲解:
-
这个信号关注的是“当前焦点项”的变化。它不一定是由用户的直接点击引起的。通过键盘的上下箭头键切换选中项、在代码中调用
setCurrentItem()
等方法,都会触发这个信号。 -
它非常有用,因为它提供了两个信息:新的当前项 (
current
) 和 之前的当前项 (previous
)。 -
如果之前没有选中项(比如第一次选中),那么
previous
参数会是nullptr
。 -
如果当前选中的项被移除或取消选中,使得没有当前项了,那么
current
参数会是nullptr
。
-
-
典型用途:
-
实现主从视图(Master-Detail View):当用户在树形结构(如文件列表、分类导航)中选择一个项目时,在右侧的详细面板中显示该项目对应的详细信息。这是最经典的用法。
-
跟踪用户的导航历史。
-
根据当前选中的项来更新菜单或工具栏的状态(如启用/禁用“删除”按钮)。
-
2. itemClicked(QTreeWidgetItem *item, int column)
-
字面意思:项目被点击。
-
触发时机:当用户用鼠标在某个项目上按下并释放(完成一次完整的点击) 时触发。
-
深入讲解:
-
这个信号非常直观,就是响应一次鼠标点击。
-
它告诉你被点击的具体项目 (
item
) 和具体列 (column
)。 -
注意:即使点击的是当前已经选中的项,这个信号依然会触发。它只关心“点击”这个动作,不关心选中状态是否改变。
-
它和
currentItemChanged
的区别是:itemClicked
是点击动作的结果,而currentItemChanged
是焦点项变化的结果。通常,一次点击会同时触发这两个信号(如果点击导致当前项改变的话)。
-
-
典型用途:
-
执行一个不需要改变“全局状态”,只与特定项目相关的即时操作。
-
当你需要知道用户点击的是哪一列时(例如,第一列是名字,第二列是复选框,你需要对点击不同列做不同处理)。
-
3. itemDoubleClicked(QTreeWidgetItem *item, int column)
-
字面意思:项目被双击。
-
触发时机:当用户在某个项目上快速连续点击两次时触发。
-
深入讲解:
-
这是“双击”操作的专用信号。
-
同样会传递被双击的项目和列。
-
需要注意的是,一次双击操作通常会先触发一次
itemClicked
信号(在第一次点击时),然后再触发itemDoubleClicked
信号。如果你的逻辑对两者都有响应,要小心不要执行重复操作。
-
-
典型用途:
-
打开或执行操作:这是最普遍的用法,例如在文件管理器中,双击一个文件就打开它;双击一个文件夹就展开/进入它。
-
启动一个项目的编辑模式。
-
4. itemEntered(QTreeWidgetItem *item, int column)
-
字面意思:鼠标进入项目区域。
-
触发时机:当鼠标光标移动进入一个项目的显示区域时触发。
-
深入讲解:
-
这个信号关注的是鼠标的悬停行为。
-
默认情况下,这个信号是关闭的,因为它的触发频率会非常高(鼠标稍微移动一下就可能触发多次)。要接收这个信号,你需要先将 QTreeWidget 的属性
mouseTracking
设置为true
。 -
由于触发频繁,在处理这个信号的槽函数中,应避免执行耗时或计算密集的操作。
-
-
典型用途:
-
实现悬停提示(ToolTip):当鼠标移动到一个项目上时,动态显示一些额外的提示信息。
-
高亮显示鼠标悬停的项目,提供更好的视觉反馈。
-
5. itemExpanded(QTreeWidgetItem *item)
-
字面意思:项目被展开。
-
触发时机:当用户点击一个项目的展开图标(那个小三角形) 或通过代码调用
expandItem()
方法,使得该项目的子项目从隐藏变为显示时触发。 -
深入讲解:
-
它只关心“展开”这个状态变化。
-
信号参数是被展开的那个父项目 (
item
)。
-
-
典型用途:
-
懒加载(Lazy Loading):这是非常核心的用途。对于一个包含大量数据的树,一开始只加载顶层节点。当用户展开某个节点时,才动态地去加载(例如从数据库或网络请求)该节点的子节点数据,这样可以极大提高程序初始化性能。
-
在项目展开后,执行一些相关的界面更新。
-
6. itemCollapsed(QTreeWidgetItem *item)
-
字面意思:项目被折叠。
-
触发时机:当用户点击一个已经展开的项目的折叠图标或通过代码调用
collapseItem()
方法,使得该项目的子项目从显示变为隐藏时触发。 -
深入讲解:
-
它是
itemExpanded
的相反操作。 -
信号参数是被折叠的那个父项目 (
item
)。
-
-
典型用途:
-
为了节省资源,在用户折叠一个节点后,可以释放该节点下所有子节点的数据(当然,要确保再次展开时能正确重新加载)。
-
在项目折叠后,更新一些相关的界面状态。
-
3.6.示例
它们的objectname是
编写代码
我们运行一下看看
接下来我们就来给3个按钮配置槽函数
我们运行一下
先看看添加顶层节点的效果
接下来我们看看添加到选中元素的效果
我们再添加一下
接着我们看看删除选中元素
很完美,没有一点问题。