个人博客地址
|----------------------------------------|
| 个人博客: 花开富贵 |
文章目录
- 个人博客地址
-
- [1 多元素控件介绍](#1 多元素控件介绍)
- [2 QListWidget](#2 QListWidget)
-
- [2.1 核心属性](#2.1 核心属性)
- [2.2 核心方法](#2.2 核心方法)
- [2.3 核心信号](#2.3 核心信号)
- [2.4 QListWidgetItem](#2.4 QListWidgetItem)
- [2.5 代码示例 - 基于 QHash 与 QDialog 的图片查看器](#2.5 代码示例 - 基于 QHash 与 QDialog 的图片查看器)
- [3 QTableWidget](#3 QTableWidget)
-
- [3.1 核心方法](#3.1 核心方法)
- [3.2 核心信号](#3.2 核心信号)
- [3.3 QTableWidgetItem 核心方法](#3.3 QTableWidgetItem 核心方法)
- [3.4 代码示例 - 基于 QTableWidget 的表格模拟器](#3.4 代码示例 - 基于 QTableWidget 的表格模拟器)
- [4 QTreeWidget](#4 QTreeWidget)
-
- [4.1 核心方法](#4.1 核心方法)
- [4.2 核心信号](#4.2 核心信号)
- [4.3 QTreeWidgetItem 属性](#4.3 QTreeWidgetItem 属性)
- [4.4 QTreeWidgetItem 核心方法](#4.4 QTreeWidgetItem 核心方法)
- [4.5 代码示例 - QTreeWidget 的动态节点与表头管理](#4.5 代码示例 - QTreeWidget 的动态节点与表头管理)
1 多元素控件介绍
Qt提供了众多的多元素控件, 其中包括:
QListWidget- 列表QListView- 列表QTableWidget- 表格QTableView- 表格QTreeWidget- 树形QTreeView- 树形
可以看到, 每一组控件都提供了对应的Widget版本与View版本;
对于Widget版本与View版本我们对其的分别为单纯的视图功能与MVC设计的控件;
-
MVCMVC是一种典型的软件架构模式, 将一套用户操作视图并进行业务处理的逻辑进行区分并统筹;分别分为
View视图,Model模型,Controller控制器;-
View用来担任控件的视图部分, 负责向用户进行显示操作;
-
Model用来负责对数据进行存储与业务处理部分;
-
Controller用来连通视图部分与模型部分, 使得二者能在一定程度上进行交互;
-

其中针对于Qt提供的View版本控件, 只提供视图, 不提供业务处理的Model与连通两者的Controller, 若是需要使用该版本的控件, 需要自行编写Model部分与Controller部分, 使用成本较高;
而Widget版本的多元素控件为MVC设计方式的控件, 其涵盖了View, Model与Controller部分, 并将三者进行整合, 从而节约使用成本;
当然若是存在一些Widget版本不存在的功能, 可以自定义Controller与Model以此实现拓展;
此处我们重点介绍Widget版本的对应控件;
2 QListWidget
该控件是Qt所提供的一个多元素控制的列表控件, 列表展出的方式为纵向的展出若干个Items, 其可以添加, 删除对应的列表项;

在ListWidget中的每个列表项都可以被选中;
该控件有可以通过QListView使用"右键->变形为"的方式变为QListWidget;

同时, QListWidget控件可以在QtDesigner中通过"右键->编辑项目"来手动添加/删除列;
2.1 核心属性
| 属性 | 说明 |
|---|---|
currentRow |
当前被选中的是第几行(由0开始计算) |
count |
一共有多少行 |
sortingEnable |
是否允许排序 |
isWrapping |
是否允许换行 |
itemAlignment |
元素的对齐方式 |
selectRectVisible |
被选中的元素矩形是否可见 |
spacing |
元素之间的间隔 |
2.2 核心方法
| 方法 | 说明 |
|---|---|
addItem(const QString &label) addItem(QListWidgetItem *item) |
列表中添加元素 该函数存在重载有两个版本 一个是传入需要显示的label, 另一个为传入一个QListWidgetItem对象指针 |
currentItem() |
返回当前选中元素Item, 返回值为QListWidgetItem * |
setCurrentItem(QListWidgetItem *item) |
设置选中哪个元素 |
setCurrentRow(int row) |
设置选中第几行的元素 |
insertItem(const QString &label, int row) insertItem(QListWidgetItem *item, int row) |
在指定的位置插入元素, 不同的重载版本 一个为传入一个QString为显示的标签名, 另一个为传入具体的QListWidgetItem*对象指针 |
item(int row) |
返回第row行的QListWidgetItem* |
takeItem(int row) |
表示删除第row行的元素, 返回被删除的QListWidgetItem*对象指针 |
2.3 核心信号
| 信号 | 说明 |
|---|---|
currentItemChanged(QListWidgetItem *current, QListWidgetItem *old) |
选中不同元素时触发, 参数表示当前选中元素与选中前的元素; |
currentRowChanged(int) |
选中不同的元素触发, 参数是当前选中元素的行数 |
itemClicked(QListWidgetItem *item) |
点击某个元素时触发 |
itemDoubleClicked(QListWidgetItem *item) |
双击某个元素时触发 |
itemEntered(QListWidgetItem *item) |
鼠标进入元素时触发 |
2.4 QListWidgetItem
该类为QListWidget控件中的子元素, 实际即为列表中每个列表项;
该控件本质上由文本与图标来构成;
其对应的方法有如下:
| 方法 | 说明 |
|---|---|
setFont |
设置字体 |
setIcon |
设置图标 |
setHidden |
设置隐藏 |
setSizeHint |
设置尺寸 |
setSelected |
设置是否被选中 |
setText |
设置文本 |
setTaxtAlignment |
设置对齐方式 |
2.5 代码示例 - 基于 QHash 与 QDialog 的图片查看器
利用QListWidget显示图片名称列表, 结合QHash存储图片数据;
实现单击列表项在主窗口Label中预览, 双击列表项弹出QDialog进行独立查看的功能;
-
所需控件
QListWidget(用于显示名称列表)QLabel(用于预览图片)
-
初始化数据与控件
为了高效地管理图片名称与图片资源的对应关系, 我们引入了
QHash. 它与 C++ STL 中的std::unordered_map非常相似, 内部基于哈希表实现, 查找速度通常快于QMap.在构造函数中, 我们初始化
elements哈希表, 并遍历它将 Key (图片名称) 添加到QListWidget中.cppWidget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) , elements(new QHash<QString, QPixmap>({ // 初始化字符和Pixmap之间的映射 {"Cat", QPixmap(":/Cat.png")}, {"Flower", QPixmap(":/Flower.png")}, {"Dog", QPixmap(":/Dog.png")}, {"Fish", QPixmap(":/Fish.png")} })) { ui->setupUi(this); // 1) 初始化控件 ui->label->setText(""); const QSize itemsSize(120, 30); // 使用迭代器遍历 QHash auto begin = elements->begin(); while(begin != elements->end()){ QListWidgetItem *item = new QListWidgetItem(begin.key()); item->setSizeHint(itemsSize); ui->listWidget->addItem(item); ++begin; } } -
设计槽函数 - 单击预览
利用
currentItemChanged信号实现预览功能;当用户点击列表项时, 从
elements哈希表中取出对应的QPixmap, 并根据 UI 中 Label 的尺寸进行缩放;cpp// 单击加载图片 void Widget::on_listWidget_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous) { (void)previous; if(!current) return; QString str = current->text(); // 根据 Label 当前的几何尺寸缩放图片, 填满 Label QPixmap tmp = elements->value(str).scaled(ui->label->geometry().size()); ui->label->setPixmap(tmp); } -
设计槽函数 - 双击独立查看
双击时我们需要弹出一个新的窗口来展示大图, 这里使用了
QDialog, 它是QMessageBox的父类, 提供了一个干净的对话框窗口;为了让图片在窗口中自动适应布局, 我们引入了
QVBoxLayout(垂直布局管理器);布局管理器能自动处理控件的位置和大小, 省去了手动计算坐标的麻烦;
cpp// 双击显示图片 void Widget::on_listWidget_itemDoubleClicked(QListWidgetItem *item) { // 使用 QDialog 显示 (QMessageBox 的父类 - 纯净弹窗) QDialog *imageDialog = new QDialog(this); imageDialog->setWindowTitle("图片查看"); // SetAttribute: 删除时自动释放内存 (非隐藏) 以免内存堆积 imageDialog->setAttribute(Qt::WA_DeleteOnClose); // 创建垂直布局管理器, 并将其父对象设置为 imageDialog QVBoxLayout *layout = new QVBoxLayout(imageDialog); // 设置边缘 (ContentsMargins) 为 0, 让图片充满窗口 layout->setContentsMargins(0, 0, 0, 0); // 创建 Label 指定 imageDialog 为父对象 QLabel *label = new QLabel(imageDialog); label->setAlignment(Qt::AlignCenter); // 让图片居中显示 // 设置图片逻辑 QString key = item->text(); if (elements->contains(key)) { QPixmap pix = elements->value(key); // 使用 KeepAspectRatio 保持长宽比缩放, SmoothTransformation 抗锯齿 QPixmap showPix = pix.scaled(1000, 700, Qt::KeepAspectRatio, Qt::SmoothTransformation); label->setPixmap(showPix); } // 将 Label 加入布局, 布局会自动管理 Label 的大小和位置 layout->addWidget(label); imageDialog->show(); // 非模态显示 } -
运行结果 (图片过大 CSDN 无法显示)

3 QTableWidget
QTableWidget控件是Qt提供的表格控件;
与QListWidget类似, 在QTableWidget中的每一个单元格都是一个QTableWidgetList;

同样的, QTableWidget控件也可以在QtDesigner中直接"右键->编辑项目"来手动添加行列;
同时该控件也可以通过View版本的控件提升而来;
3.1 核心方法
| 属性 | 说明 |
|---|---|
item(int row, int column) |
根据行数列数获取指定的QTableWidgetItem* |
setItem(int row, int column, QTableWidget*) |
根据行数列数设置表格中的元素 |
currentItem() |
返回被选中的元素QTableWidgetItem* |
currentRow() |
返回被选中的元素是第几行 |
currentColumn() |
返回被选中的元素是第几列 |
row(QTableWidgetItem*) |
获取指定item是第几行 |
column(QTableWidgetItem*) |
获取指定item是第几列 |
rowCount() |
获取行数 |
columnCount() |
获取列数 |
insertRow(int row) |
在第row行处插入新行, 新行成为第row行 |
insertColumn(int column) |
在第column列处插入新列, 新列成为第column列 |
removeRow(int row) |
删除第row行 |
removeColumn(int column) |
删除第column列 |
setHorizontalHeaderItem(int column, QTableWidget*) |
设置指定列的表头 |
setVerticalHeaderItem(int row, QTableWidget*) |
设置指定行的表头 |
3.2 核心信号
| 信号 | 说明 |
|---|---|
cellClicked(int row, int column) |
点击单元格时触发 |
cellDoubleClicked(int row, int column) |
双击单元格时触发 |
cellEntered(int row, int column) |
鼠标进入单元格时触发 |
currentCellChanged(int, row, int column, int previousRow, intpreviousColumn) |
选中不同单元格时触发, 参数给出当前的行列信息与前一列的行列信息 |
3.3 QTableWidgetItem 核心方法
| 方法 | 说明 |
|---|---|
row() |
获取当前是第几行 |
column() |
获取当前是第几列 |
setText(const QString&) |
设置文本 |
setTextAlignment(int) |
设置文本对齐 |
setIcon(const QIcon&) |
设置图标 |
setSelected(bool) |
设置被选中 |
setSizeHints(const QSize&) |
设置尺寸 |
setFont(const QFont&) |
设置字体 |
3.4 代码示例 - 基于 QTableWidget 的表格模拟器
利用QTableWidget实现一个表格功能, 表格存在四个PushButton, 分别用于:
- 行的增加
- 列的增加
- 行的删除
- 列的删除
其中关于行的增加直接以"第n行/条", n表示该条数据的顺序, 列的增加需要有一个QLineEdit使用户可以获取列名, 行列的删除都由最后一条由后往前删, 表格有几条硬性规则:
- 行列删除时只剩下默认行列时不允许删除操作(列为
3, 行为1)- 当
QLineEdit中没有内容时无法创建新列- 一个列新创建后, 对应的
QLineEdit内容将会被清空;
-
所需控件
-
QPushButton用于行列的增删操作;
-
QLineEdit用于获取列名;
-
QTableWidget具体的表格整体;

-
-
初始化控件
控件需要进行初始化, 主要初始化的部分是默认的行列, 与
LineEdit的placeHolderText以及三个按钮的默认禁用状态;- 两个删除按钮在只剩默认行列时不允许进行对应删除
- 一个
column的增加操作需要LineEdit中存在内容否则禁用
cppWidget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); /* # 1) 初始化UI状态与基础数据 设置占位文本, 重命名按钮, 并预设表格的基础结构(3列1行); */ ui->lineEdit->setPlaceholderText("需要增加的列名"); ui->pushButton_addCol->setText("增加列"); ui->pushButton_addRow->setText("增加行"); ui->pushButton_delCol->setText("删除列"); ui->pushButton_delRow->setText("删除行"); // 初始化固定的三列: ID, 姓名, 性别 QVector<QString> normalColumns({"ID", "姓名", "性别"}); for(int i=0;i<normalColumns.size();++i){ ui->tableWidget->insertColumn(i); // 在第i个位置插入列 ui->tableWidget->setHorizontalHeaderItem(i, new QTableWidgetItem(normalColumns[i])); // 设置表头 } // 初始化默认的一行 ui->tableWidget->insertRow(0); ui->tableWidget->setVerticalHeaderItem(0, new QTableWidgetItem("第1条")); /* # 2) 设置按钮的初始保护状态 刚启动时只有基础行列, 不允许删除, 且输入框为空也不允许添加列; */ ui->pushButton_delCol->setEnabled(false); ui->pushButton_delRow->setEnabled(false); ui->pushButton_addCol->setEnabled(false); } -
输入框的非空校验
当输入框为非空时,
column的增加按钮的Enable状态才为可用, 否则不可用;主要监听
QLineEdit的textChanged信号;cppvoid Widget::on_lineEdit_textChanged(const QString &arg1) { /* # 3) 输入框非空校验 监听输入框变化, 只有当用户输入了列名后, 才激活"增加列"按钮, 防止添加空表头; */ if(!arg1.size()) ui->pushButton_addCol->setEnabled(false); else ui->pushButton_addCol->setEnabled(true); } -
增加列并判断是否解除删除列的禁用状态
获取输入框内容, 将输入框内容作为新列的表头;
当新列被插入后, 查询当前列数是否满足允许解除删除列的
PushButton的禁用状态;cppvoid Widget::on_pushButton_addCol_clicked() { /* # 4) 动态增加列 获取输入框内容, 在表格末尾追加一列, 并更新表头文字; */ QString str = ui->lineEdit->text(); // 在当前总列数的位置插入新列(即追加在最后) ui->tableWidget->insertColumn(ui->tableWidget->columnCount()); // 设置新列的表头 ui->tableWidget->setHorizontalHeaderItem( ui->tableWidget->columnCount()-1, new QTableWidgetItem(str)); ui->lineEdit->clear(); // 清空输入框, 方便下一次输入 /* # 5) 更新计数与按钮状态 列数增加后, 如果超过了基础的3列, 则允许使用"删除列"按钮; */ if(ui->tableWidget->columnCount()>3) ui->pushButton_delCol->setEnabled(true); else ui->pushButton_delCol->setEnabled(false); } -
增加行并判断是否解除删除行的禁用状态
增加行可以直接进行增加, 其中行表头采用"第
n条"的方式进行命名, 其中n为i(当前行下标+1);cppvoid Widget::on_pushButton_addRow_clicked() { /* # 6) 动态增加行 逻辑同增加列, 但在垂直表头显示"第N条"作为标识; */ QString str = "第"+QString::number(ui->tableWidget->rowCount()+1)+"条"; ui->tableWidget->insertRow(ui->tableWidget->rowCount()); ui->tableWidget->setVerticalHeaderItem( ui->tableWidget->rowCount()-1, new QTableWidgetItem(str)); if(ui->tableWidget->rowCount()>1) ui->pushButton_delRow->setEnabled(true); else ui->pushButton_delRow->setEnabled(false); } -
删除行/列
直接删除末尾的行/列, 在数值更新后判断是否禁用删除按钮;
cppvoid Widget::on_pushButton_delCol_clicked() { /* # 7) 动态删除列 移除最后一列, 并判断剩余列数; 如果回到了基础的3列, 则禁用删除按钮; */ ui->tableWidget->removeColumn(ui->tableWidget->columnCount()-1); if(ui->tableWidget->columnCount()>3) ui->pushButton_delCol->setEnabled(true); else ui->pushButton_delCol->setEnabled(false); } void Widget::on_pushButton_delRow_clicked() { /* # 8) 动态删除行 移除最后一行, 若只剩最后一条基础数据, 则禁用删除按钮以保护底线; */ ui->tableWidget->removeRow(ui->tableWidget->rowCount()-1); if(ui->tableWidget->rowCount()>1) ui->pushButton_delRow->setEnabled(true); else ui->pushButton_delRow->setEnabled(false); } -
运行结果

4 QTreeWidget
QTreeWidget是Qt提供的树形结构的多元素控件, 其类似于QListWidget;
但在结构划分上, QTreeWidget采用树形结构, 类似于我们常用的文件管理器;
同时虽然该树形结构是一种树形结构, 但其未体现出树的根节点, 更像是树的子树;

通常可以创建的是TopLevelItem, 与其的子节点ChildItem;

该控件同样可以使用View控件通过"右键->提升为"的方式进行提升;
同时"右键->编辑项目"可以对该控件进行预先设置;
4.1 核心方法
| 方法 | 说明 |
|---|---|
clear |
清空所有子节点 |
addTopLevelItem(QTreeWidgetItem* item) |
新增顶层节点 |
topLevelItem(int index) |
获取指定下标的顶层节点 |
topLevelItemCount() |
获取顶层节点个数 |
indexOfTopLevelItem(QTreeWidgetItem* item) |
查询指定节点是顶层节点中的下标 |
takeTopLevelItem(int index) |
删除指定的顶层节点, 返回QTreeWidgetItem*表示被删除的元素 |
currentItem() |
获取到当前选中的节点, 返回QTreeWidgetItem* |
setCurrentItem(QTreeWidgetItem* item) |
选中指定节点 |
setExpanded(bool) |
展开/关闭节点 |
setHeaderLabel(const QString& text) |
设置QTreeWidget的header名称 |
4.2 核心信号
| 信号 | 说明 |
|---|---|
currentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* old) |
切换选中元素时触发 |
itemClicked(QTreeWidgetItem* item, int col) |
点击元素时触发 |
itemDoubleClicked(QTreeWidgetItem* item, int col) |
双击元素时触发 |
itemEntered(QTreeWidgetItem* item, int col) |
鼠标进入时触发 |
itemExpanded(QRteeWidgetItem* item) |
元素被展开时触发 |
itemCollapsend(QTreeWidgetItem* item) |
元素被折叠时触发 |
4.3 QTreeWidgetItem 属性
| 属性 | 说明 |
|---|---|
text |
持有的文本 |
textAlignment |
文本对齐方式 |
icon |
持有的图表 |
font |
文本字体 |
hiddent |
是否隐藏 |
disabled |
是否禁用 |
expand |
是否展开 |
sizeHint |
尺寸大小 |
selected |
是否选中 |
4.4 QTreeWidgetItem 核心方法
| 方法 | 说明 |
|---|---|
addChild(QTreeWidgetItem* child) |
新增子节点 |
childCount() |
子节点的个数 |
child(int index) |
获取指定下标的子节点, 返回QTReeWidgetItem* |
tackChild(int index) |
删除对应下标的子节点 |
removeChild(QTreeWidgetItem) |
删除对应的子节点 |
parent() |
获取该元素的父节点 |
4.5 代码示例 - QTreeWidget 的动态节点与表头管理
创建一个基于 QTreeWidget 的综合管理工具; 不仅实现对树形节点 (顶层项, 子项)的增删改查, 还实现了对表格结构(增加列, 修改列名)的动态调整, 演示了如何构建一个高容错的交互界面;
-
所需控件
QTreeWidget(核心控件)QLineEdit(输入名称)QPushButton(x6: 添加顶层/子节点/列, 删除列/节点, 重命名)
-
初始化与信号连接
在构造函数中, 我们需要初始化树的基础状态(1列), 并设置交互逻辑的"安全锁"(默认禁用按钮); 最关键的是, 为了实现修改写错的表头 , 我们需要连接
QHeaderView的双击信号;cppWidget::Widget(QWidget *parent) : ... { ui->setupUi(this); // 1. 初始化树控件状态 ui->treeWidget->clear(); ui->treeWidget->setColumnCount(1); // 默认为1列 ui->treeWidget->setHeaderLabels(QStringList{"项目列表"}); // 2. 初始化按钮状态 (防呆设计) ui->pushButton_addChild->setEnabled(false); // ... (其他按钮禁用代码略) // 3. 【高级技巧】连接表头双击信号 (用于修正列名) connect(ui->treeWidget->header(), &QHeaderView::sectionDoubleClicked, this, &Widget::on_header_doubleClicked); // 4. 连接选择变化信号 (用于控制删除按钮) connect(ui->treeWidget, &QTreeWidget::itemSelectionChanged, this, &Widget::on_treeWidget_itemSelectionChanged); } -
节点管理逻辑 (增/删/改)
这里展示了
QTreeWidget最核心的三种操作;- 添加顶层项 : 使用
addTopLevelItem; - 添加子项 : 必须先获取
currentItem, 然后调用item->addChild; - 构造函数陷阱 : 必须使用
QStringList构造QTreeWidgetItem, 即使只有一列;
cpp// 添加子项目 void Widget::on_pushButton_addChild_clicked() { QTreeWidgetItem *current = ui->treeWidget->currentItem(); // 安全检查: 必须选中父节点 if(!current) return; QString str = ui->lineEdit->text(); // 注意: 构造函数必须传 QStringList QTreeWidgetItem *child = new QTreeWidgetItem(QStringList{str}); current->addChild(child); current->setExpanded(true); // 自动展开方便查看 ui->lineEdit->clear(); } - 添加顶层项 : 使用
-
表头/列管理逻辑 (容错处理)
这是针对"列加错了"或"列名写错了"的补救方案;
- 增加列 : 通过
setColumnCount(n+1)扩展空间, 并设置 Header 文本; - 修正列名: 响应表头双击事件, 弹出输入框修改;
cpp// 增加新列 (Add Table) void Widget::on_pushButton_addTable_clicked() { QString str = ui->lineEdit->text(); int cols = ui->treeWidget->columnCount(); ui->treeWidget->setColumnCount(cols + 1); // 扩容 ui->treeWidget->headerItem()->setText(cols, str); // 命名 } // 双击表头修改 (Fix Header) void Widget::on_header_doubleClicked(int index) { QString oldName = ui->treeWidget->headerItem()->text(index); // 使用 QInputDialog 获取新名字... } - 增加列 : 通过
-
运行结果

-
完整代码
cpp#include "widget.h" #include "ui_widget.h" #include <QString> #include <QStringList> #include <QMessageBox> // 引入消息框用于提示 Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); // 1) 初始化界面状态 ui->treeWidget->clear(); // 设置初始列数为1, 并设置默认表头 ui->treeWidget->setColumnCount(1); ui->treeWidget->setHeaderLabels(QStringList{"项目列表"}); ui->lineEdit->setPlaceholderText("请输入名称"); ui->lineEdit->setClearButtonEnabled(true); ui->pushButton_addChild->setText("添加子项"); ui->pushButton_addTopLevel->setText("添加根项"); ui->pushButton_deleteItem->setText("删除项目"); ui->pushButton_addTable->setText("增加新列"); // addTable 理解为增加列 ui->pushButton_rename->setText("重命名"); ui->pushButton_removeTable->setText("删除列"); // 2) 初始禁用所有操作按钮 ui->pushButton_addChild->setEnabled(false); ui->pushButton_addTopLevel->setEnabled(false); ui->pushButton_deleteItem->setEnabled(false); ui->pushButton_addTable->setEnabled(false); ui->pushButton_rename->setEnabled(false); // 【重要】连接选择改变信号, 以便在用户点击树节点时, 判断"删除"按钮是否可用 // 如果没有这一步, 用户未选中节点就点删除会很奇怪 connect(ui->treeWidget, &QTreeWidget::itemSelectionChanged, this, &Widget::on_treeWidget_itemSelectionChanged); } Widget::~Widget() { delete ui; } // --------------------------------------------------------- // 状态控制逻辑 // --------------------------------------------------------- // 文本框内容改变: 控制 "添加" 类按钮 void Widget::on_lineEdit_textChanged(const QString &arg1) { bool hasText = !arg1.isEmpty(); // 只要有文字, 就可以添加顶层项, 增加列 ui->pushButton_addTopLevel->setEnabled(hasText); ui->pushButton_addTable->setEnabled(hasText); // 对于"添加子项"和"重命名", 不仅要有文字, 还必须选中了一个父节点 // 这里简单处理, 先启用, 在点击函数里再做判断 ui->pushButton_addChild->setEnabled(hasText); ui->pushButton_rename->setEnabled(hasText); } // 树节点选择改变: 控制 "删除" 按钮 // 只有选中了东西, 才能删除 void Widget::on_treeWidget_itemSelectionChanged() { bool hasSelection = !ui->treeWidget->selectedItems().isEmpty(); ui->pushButton_deleteItem->setEnabled(hasSelection); } // --------------------------------------------------------- // 核心功能逻辑 // --------------------------------------------------------- // 1. 添加顶层项目 (Root) void Widget::on_pushButton_addTopLevel_clicked() { QString str = ui->lineEdit->text(); if(str.isEmpty()) return; // 使用 QStringList 构造函数 QTreeWidgetItem *item = new QTreeWidgetItem(QStringList{str}); ui->treeWidget->addTopLevelItem(item); ui->lineEdit->clear(); } // 2. 增加新表 (增加列 Column) void Widget::on_pushButton_addTable_clicked() { QString str = ui->lineEdit->text(); if(str.isEmpty()) return; // 获取当前有多少列 int colCount = ui->treeWidget->columnCount(); // 增加一列 ui->treeWidget->setColumnCount(colCount + 1); // 设置新一列的表头名称 // headerItem() 获取表头指针, setText(列索引, 名称) ui->treeWidget->headerItem()->setText(colCount, str); ui->lineEdit->clear(); } // 3. 添加子项目 (Child) void Widget::on_pushButton_addChild_clicked() { // 获取当前选中的节点 QTreeWidgetItem *currentItem = ui->treeWidget->currentItem(); //如果没有选中父节点, 就不能添加子节点 if(!currentItem) { QMessageBox::warning(this, "提示", "请先选中一个项目作为父节点!"); return; } QString str = ui->lineEdit->text(); if(str.isEmpty()) return; // 创建新节点 QTreeWidgetItem *childItem = new QTreeWidgetItem(QStringList{str}); // 挂载到当前选中的节点下 currentItem->addChild(childItem); // 自动展开父节点, 以便看到刚添加的子项 currentItem->setExpanded(true); ui->lineEdit->clear(); } // 4. 删除项目 void Widget::on_pushButton_deleteItem_clicked() { // 获取当前选中的节点 QTreeWidgetItem *currentItem = ui->treeWidget->currentItem(); if(!currentItem) return; // 在 Qt 中, 删除 QTreeWidgetItem 最简单的办法就是直接 delete 指针 // Qt 会自动处理它与父节点或 TreeWidget 的断开逻辑 delete currentItem; // 删除后禁用删除按钮, 防止误触 ui->pushButton_deleteItem->setEnabled(false); } // 5. 重命名 void Widget::on_pushButton_rename_clicked() { QTreeWidgetItem *currentItem = ui->treeWidget->currentItem(); if(!currentItem) { QMessageBox::warning(this, "提示", "请先选中要重命名的项目!"); return; } QString str = ui->lineEdit->text(); // 修改当前节点第0列的文字 // 如果你想重命名选中的那一列, 可以用 ui->treeWidget->currentColumn(); currentItem->setText(0, str); ui->lineEdit->clear(); } // 槽函数: 删除最后一列 void Widget::on_pushButton_removeTable_clicked() { int currentCount = ui->treeWidget->columnCount(); // 保护机制: 至少保留 1 列 if (currentCount > 1) { ui->treeWidget->setColumnCount(currentCount - 1); } else { QMessageBox::information(this, "提示", "至少保留一列!"); } }