对于Qt:QTableWidget常见属性以及QTableWidgetItem类的解析

开篇介绍:

hello 大家,本篇博客我们来学习QTableWidget常见属性以及QTableWidgetItem类。

在 Qt 桌面应用开发中,当我们需要展示和管理 "一维列表"(比如联系人列表、播放列表)时,QListWidget 是我们的首选;但当我们需要展示和管理更复杂的 "二维表格数据"(比如学生信息表、商品库存表、财务报表)时 ------ 也就是数据既有 "行" 又有 "列",每个数据都有明确的 "行号 + 列号" 定位时,我们就需要一个更强大的控件:QTableWidget(表格控件)。

QTableWidget 就像 "我们平时用的 Excel 表格"------ 它由若干行和若干列组成,行和列的交叉点就是一个 "单元格";你可以设置表格有多少行、多少列,可以给每一列起个名字(列标题),给每一行起个名字(行标题);你可以在任意单元格里填写文字、贴图标、改字体、设置对齐方式;你可以点击单元格、双击单元格、鼠标悬浮在单元格上;你可以动态插入新的一行、新的一列,也可以删除某一行、某一列。

而 QTableWidget 中的每一个 "单元格",都是由 QTableWidgetItem(表格项类) 来表示的 ------QTableWidgetItem 是 QTableWidget 的最小组成单元,对应表格中 "行 + 列" 定位的单个单元格;它的属性和 QListWidgetItem 几乎一模一样,只不过多了 "列号" 的概念。

很多新手刚接触 QTableWidget 和 QTableWidgetItem 时,会觉得它们比 QListWidget 复杂 ------ 毕竟多了一维,要同时考虑行和列。但别担心!只要你掌握了 QListWidget,学习 QTableWidget 就会非常轻松,因为它们的核心逻辑是相通的:QListWidget 是 "一维数组",QTableWidget 是 "二维数组";QListWidgetItem 是 "一维数组的元素",QTableWidgetItem 是 "二维数组的元素"。

这篇文章我会先讲 QTableWidgetItem 类的核心方法 (row、column、setText、setTextAlignment、setIcon、setSelected、setSizeHint、setFont),再讲 QTableWidget 的核心方法 (item、setItem、currentItem、currentRow、currentColumn、row、column、rowCount、columnCount、insertRow、insertColumn、removeRow、removeColumn、setHorizontalHeaderItem、setVerticalHeaderItem),接着讲 QTableWidget 的核心交互信号 (cellClicked、cellDoubleClicked、cellEntered、currentCellChanged),最后是综合示例。

话不多说,我们正式开始!


第一章 先搞懂基础:QTableWidget 和 QTableWidgetItem 是什么?

在讲具体内容之前,我们必须先搞懂两个最基础、最重要的问题:QTableWidget 是用来做什么的?QTableWidgetItem 是用来做什么的?以及,它们和 QTableView 的关系是什么?

1.1 QTableWidget 的核心定位

QTableWidget 是 Qt Widgets 模块中用于展示和管理二维表格数据的核心通用控件 ------ 它继承自 QTableView(表格视图),但比 QTableView 更简单、更易用,因为它内置了 "单元格管理" 的功能,不需要你手动实现数据模型(Model)和视图(View)的分离。

通俗理解:QTableWidget 就像 "一个简化版的 Excel 表格"------ 它是一个二维的网格,由 "行" 和 "列" 组成;行是纵向的,列是横向的;行和列的交叉点就是一个 "单元格";你可以在单元格里填数据、改样式;你可以增加行、增加列、删除行、删除列;你可以给列起标题(比如 "姓名""年龄""学号"),给行起标题(比如 "第一行""第二行")。

QTableWidget 内置了非常多的功能,不需要你手动实现:

  • 它支持按 "行号 + 列号" 精准定位和操作单元格;
  • 它支持获取当前选中的单元格、选中的行号、选中的列号;
  • 它支持统计表格的总行数、总列数;
  • 它支持在指定位置插入新行、新列,删除指定行、指定列;
  • 它支持自定义水平表头(列标题)和垂直表头(行标题);
  • 它支持丰富的交互信号:单元格点击、双击、鼠标悬浮、选中变更等;
  • 它的样式可以通过 QSS(Qt 样式表)完全自定义。

总之,QTableWidget 是桌面端 "展示和管理二维表格数据" 场景的通用首选组件------ 只要是想展示一个表格,用 QTableWidget 就对了。

1.2 QTableWidgetItem 的核心定位

QTableWidgetItem 是 Qt 中表示 QTableWidget 中单个单元格的核心类------ 它是 QTableWidget 的最小组成单元,每个 QTableWidgetItem 对应表格中 "行 + 列" 定位的单个单元格。

通俗理解:QTableWidgetItem 就像 "Excel 表格里的每一个小格子"------ 这个小格子里可以写文字(setText),可以贴图标(setIcon),可以设置字体(setFont),可以设置文字对齐方式(setTextAlignment);你可以把这个格子标记为 "已选中"(setSelected),可以设置这个格子的大小(setSizeHint);你还可以查询这个格子在第几行(row)、第几列(column)。

QTableWidgetItem 的核心特征和 QListWidgetItem 几乎一模一样,只是多了 "列号" 的概念:

  • 它本质上是一个 "文本 + 图标" 的组合体 ------ 这是它最核心的视觉内容;
  • 每个单元格可以独立设置样式和状态------ 你可以让第一个单元格是红色字体,第二个单元格是蓝色字体,第三个单元格带图标;
  • 它支持查询自身的行号和列号 ------ 未加入表格时返回 -1;
  • 它的内存由 QTableWidget 管理(通过 setItem 添加后)------ 通过 removeRow/removeColumn 移除时会自动释放。

1.3 QTableWidget 和 QTableView 的关系(必知!)

和 QListWidget 与 QListView 的关系一样:

  • QTableWidget 是 QTableView 的子类 ------ 它在 QTableView 的基础上,内置了一个简单的数据模型(QStandardItemModel),让你可以直接操作单元格,而不需要手动实现 Model/View 架构;
  • QTableWidget 比 QTableView 更简单、更易用------ 如果你只是想展示一个简单的表格,不需要复杂的数据模型,用 QTableWidget 就够了;如果你需要展示大量数据(比如成千上万条),或者需要自定义数据模型,再考虑用 QTableView + 自定义 Model。

1.4 一个超级重要的注意事项(开篇就讲,刻在脑子里!)

在正式开始之前,有一个超级重要、新手最容易踩坑、一踩就无效的注意事项,必须开篇就讲,刻在脑子里:

严格注意!在插入条目(setItem)之前,必须先指明表格的行列数量才行哦!

你可以用 setRowCount() 设置行数,用 setColumnCount() 设置列数;

或者用 insertRow() 和 insertColumn() 先插入行列;

否则,你设置的单元格可能无效,界面上看不到内容!

通俗理解:你要先把 "表格的格子画好"(设置行列数),才能往 "格子里填东西"(设置单元格);如果格子都没画好,你填的东西就没地方放,界面上自然看不到。

这个注意事项超级重要,后面讲 setItem 时我还会再强调,但现在必须先记住!


第二章 QTableWidgetItem 类核心方法详解

好,我们正式开始!按照你提供的顺序,我们首先讲 QTableWidgetItem 类的核心方法 ------ 因为要往 QTableWidget 里填单元格,首先得搞懂单元格本身怎么设置。QTableWidgetItem 的方法和 QListWidgetItem 几乎一模一样,只是多了 row() 和 column() 两个方法,用来查询单元格的位置。


2.1 方法一:row ()------ 获取当前单元格所属的行号

2.1.1 方法的核心定义

row() 是 QTableWidgetItem 用于获取当前单元格所属行号的核心位置查询方法 ------ 行号从 0 开始计数(第一行是 0,第二行是 1,以此类推);若条目未添加到表格中,返回值为 -1。

通俗理解:row() 就像 "问这个小格子:'你在表格的第几行呀?'"------ 它会告诉你一个数字,从 0 开始;如果这个小格子还没放到表格里,它就说 "我不知道"(返回 -1)。

这里有几个超级重要的规则,必须牢记:

  1. 行号从 0 开始计数!(超级重要!说三遍!) :
    • 第一行的行号是 0,第二行是 1,第三行是 2,...,第 N 行是 N-1;
    • 用户视角的 "第 1 行" 对应代码里的 row=0,这点新手非常容易搞错!
  2. 未加入表格返回 -1 :条目创建后,未通过 setItem() 添加到表格时,返回 -1;
  3. 位置联动(超级重要!) :
    • 条目添加到表格后,行号随表格行增删自动更新;
    • 比如删除了上方的行,这个条目的行号会自动 -1;
    • 比如在上方插入了新行,这个条目的行号会自动 +1;
  4. 等价方法 :table->row(item) 和 item->row() 是等价的,结果完全一致。
2.1.2 关联 API 详解(逐词逐句,零模糊)
1. 获取当前单元格所属行号:int row () const

函数原型:

复制代码
int QTableWidgetItem::row() const;

逐词逐句底层解析:

  • int:返回值类型,返回行号;
  • QTableWidgetItem:::说明这个函数是 QTableWidgetItem 类的成员函数,只能用 QTableWidgetItem 对象调用;
  • row():函数名,很直观,就是 "获取行号" 的意思;
  • const:常成员函数,不会修改条目状态。

返回值说明:

  • 返回 int 类型的整数;
  • 有效范围:0 ≤ row < rowCount()(已加入表格时);
  • 未加入表格时返回 -1。
2.1.3 使用示例
复制代码
#include <QTableWidgetItem>
#include <QDebug>

// 假设表格已经设置了 3 行 3 列
// 获取第 2 行(索引 1)、第 3 列(索引 2)的单元格
QTableWidgetItem* item = ui->tableWidget->item(1, 2);
if (item != nullptr) { // 判空
    int rowNum = item->row();
    qDebug() << "单元格行号(代码):" << rowNum; // 输出:1
    qDebug() << "单元格行号(用户):" << rowNum + 1; // 行号+1 适配用户习惯,输出:2
}
2.1.4 关键注意事项(必知!)
  1. 行号从 0 开始!(超级重要!说三遍!):用户视角的第 1 行对应代码的 0;
  2. 未加入表格返回 -1;
  3. 位置联动(超级重要!):行号随表格行增删自动更新;
  4. 等价于 table->row (item)。

2.2 方法二:column ()------ 获取当前单元格所属的列号

2.2.1 方法的核心定义

column() 是 QTableWidgetItem 用于获取当前单元格所属列号的核心位置查询方法 ------ 列号从 0 开始计数(第一列是 0,第二列是 1,以此类推);若条目未添加到表格中,返回值为 -1。

通俗理解:column() 就像 "问这个小格子:'你在表格的第几列呀?'"------ 它会告诉你一个数字,从 0 开始;如果这个小格子还没放到表格里,它就说 "我不知道"(返回 -1)。

这里有几个超级重要的规则,必须牢记:

  1. 列号从 0 开始计数!(超级重要!说三遍!) :
    • 第一列的列号是 0,第二列是 1,第三列是 2,...,第 N 列是 N-1;
    • 用户视角的 "第 1 列" 对应代码里的 column=0;
  2. 未加入表格返回 -1 :条目创建后,未通过 setItem() 添加到表格时,返回 -1;
  3. 位置联动(超级重要!) :
    • 条目添加到表格后,列号随表格列增删自动更新;
    • 比如删除了左侧的列,这个条目的列号会自动 -1;
    • 比如在左侧插入了新列,这个条目的列号会自动 +1;
  4. 等价方法 :table->column(item) 和 item->column() 是等价的,结果完全一致。
2.2.2 关联 API 详解(逐词逐句,零模糊)
1. 获取当前单元格所属列号:int column () const

函数原型:

复制代码
int QTableWidgetItem::column() const;

逐词逐句底层解析:

  • int:返回值类型,返回列号;
  • QTableWidgetItem:::成员函数;
  • column():函数名,"获取列号" 的意思;
  • const:常成员函数。

返回值说明:

  • 返回 int 类型的整数;
  • 有效范围:0 ≤ column < columnCount()(已加入表格时);
  • 未加入表格时返回 -1。
2.2.3 使用示例
复制代码
#include <QTableWidgetItem>
#include <QDebug>

// 假设表格已经设置了 3 行 3 列
// 遍历表格第一行(索引 0),打印每个单元格的列号和文本
for (int col = 0; col < ui->tableWidget->columnCount(); ++col) {
    QTableWidgetItem* item = ui->tableWidget->item(0, col);
    if (item != nullptr) { // 判空
        qDebug() << "列号(代码):" << item->column()
                 << ",列号(用户):" << item->column() + 1
                 << ",文本:" << item->text();
    }
}
2.2.4 关键注意事项(必知!)
  1. 列号从 0 开始!(超级重要!说三遍!):用户视角的第 1 列对应代码的 0;
  2. 未加入表格返回 -1;
  3. 位置联动(超级重要!):列号随表格列增删自动更新;
  4. 等价于 table->column (item)。

2.3 方法三:setText () & text ()------ 设置 / 获取单元格文本

这两个方法和 QListWidgetItem 的 setText()/text() 几乎一模一样,我们简单回顾一下,重点讲和表格相关的注意事项。

2.3.1 方法的核心定义

setText() 用于设置单元格的显示文本,支持普通字符串、HTML 富文本格式;text() 用于获取当前单元格显示的文本。

通俗理解:setText() 就像 "在这个小格子里写字";text() 就像 "读这个小格子里写的是什么字"。

表格相关的关键注意事项:

  1. 文本过长时自动截断 :文本过长时,表格会自动截断并显示省略号,可通过 setSizeHint() 扩大单元格尺寸,或通过 resizeColumnsToContents() 自动调整列宽来避免;
  2. 富文本支持 :仅支持基础 HTML 标签(<b>/<i>/<font>/<br> 等),复杂标签可能无法正常渲染;
  3. 编码适配:确保文本为 UTF-8 编码,避免中文乱码。
2.3.2 使用示例
复制代码
#include <QTableWidgetItem>

// 假设表格已经设置了行列数
// 示例1:设置普通文本
QTableWidgetItem* item1 = new QTableWidgetItem();
item1->setText("普通文本单元格");
ui->tableWidget->setItem(0, 0, item1);

// 示例2:设置富文本(红色加粗)
QTableWidgetItem* item2 = new QTableWidgetItem();
item2->setText("<font color='red'><b>富文本单元格(红色加粗)</b></font>");
ui->tableWidget->setItem(0, 1, item2);

// 示例3:获取单元格文本
QString text = item1->text();
qDebug() << "单元格文本:" << text;

2.4 方法四:setTextAlignment ()------ 设置单元格文本对齐方式

这个方法和 QListWidgetItem 的 setTextAlignment() 几乎一模一样,我们简单回顾一下。

2.4.1 方法的核心定义

setTextAlignment() 用于控制文本在单元格内部的水平 + 垂直对齐位置,默认对齐方式为 Qt::AlignLeft | Qt::AlignVCenter(左对齐 + 垂直居中);对齐效果需结合单元格尺寸(setSizeHint)或列宽 / 行高调整才能明显体现。

核心对齐枚举值(Qt::Alignment)(和之前完全一样):

枚举值 功能说明
Qt::AlignLeft 水平左对齐(默认);
Qt::AlignRight 水平右对齐;
Qt::AlignHCenter 水平居中;
Qt::AlignCenter 水平 + 垂直居中(等价于 `AlignHCenter AlignVCenter`);
Qt::AlignTop 垂直顶部对齐;
Qt::AlignBottom 垂直底部对齐;
Qt::AlignVCenter 垂直居中(默认);
2.4.2 使用示例
复制代码
#include <QTableWidgetItem>
#include <QSize>
#include <Qt>

// 假设表格已经设置了行列数
// 示例1:设置单元格文本水平+垂直居中
QTableWidgetItem* item1 = new QTableWidgetItem("居中对齐");
item1->setTextAlignment(Qt::AlignCenter);
item1->setSizeHint(QSize(100, 50)); // 扩大单元格尺寸,对齐效果更明显
ui->tableWidget->setItem(1, 0, item1);

// 示例2:设置文本右对齐+垂直底部对齐
QTableWidgetItem* item2 = new QTableWidgetItem("右底对齐");
item2->setTextAlignment(Qt::AlignRight | Qt::AlignBottom);
ui->tableWidget->setItem(1, 1, item2);

2.5 方法五:setIcon () & icon ()------ 设置 / 获取单元格图标

这个方法和 QListWidgetItem 的 setIcon()/icon() 几乎一模一样,我们简单回顾一下,重点讲和表格相关的注意事项。

2.5.1 方法的核心定义

setIcon() 用于为单元格添加 / 修改图标,图标默认显示在文本左侧;icon() 用于获取当前单元格的图标。

表格相关的关键注意事项:

  1. 图标显示尺寸由 QTableWidget 全局控制!(超级重要!) :
    • 单个单元格无法单独设置图标的显示尺寸;
    • 所有单元格的图标显示尺寸由 QTableWidget 的 setIconSize() 方法全局统一控制;
  2. 支持多种图标来源:资源文件、本地图片、系统图标等;
  3. QIcon 自动适配状态:自动适配单元格选中 / 未选中状态。
2.5.2 使用示例
复制代码
#include <QTableWidgetItem>
#include <QIcon>
#include <QApplication>
#include <QStyle>

// 先设置 QTableWidget 的全局图标尺寸(超级重要!所有单元格共用!)
ui->tableWidget->setIconSize(QSize(24, 24)); // 图标显示为 24x24 像素

// 假设表格已经设置了行列数
// 示例1:使用资源文件图标
QTableWidgetItem* item1 = new QTableWidgetItem("资源图标");
item1->setIcon(QIcon(":/images/icon.png"));
ui->tableWidget->setItem(2, 0, item1);

// 示例2:使用系统图标
QTableWidgetItem* item2 = new QTableWidgetItem("系统图标");
QIcon systemIcon = QApplication::style()->standardIcon(QStyle::SP_FileIcon);
item2->setIcon(systemIcon);
ui->tableWidget->setItem(2, 1, item2);

2.6 方法六:setSelected () & isSelected ()------ 设置 / 获取单元格是否选中

这个方法和 QListWidgetItem 的 setSelected()/isSelected() 几乎一模一样,我们简单回顾一下,重点讲和表格相关的注意事项。

2.6.1 方法的核心定义

setSelected() 用于控制单元格的选中状态,选中的单元格会按照系统 / 自定义样式高亮显示;isSelected() 用于判断单元格是否被选中。

表格相关的关键注意事项:

  1. 受表格选择模式控制 :仅在非 NoSelection 模式下,选中状态才会生效;
  2. 受表格选择行为控制 :
    • 若表格开启 setSelectionBehavior(QAbstractItemView::SelectRows),选中单元格会同步选中整行;
    • 若开启 SelectColumns,选中单元格会同步选中整列;
  3. 信号触发 :调用 setSelected() 会触发 QTableWidget::itemSelectionChanged() 信号。
2.6.2 使用示例
复制代码
#include <QTableWidgetItem>
#include <QAbstractItemView>

// 假设表格已经设置了行列数
// 示例1:设置表格为单选模式,选中指定单元格
ui->tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
QTableWidgetItem* item1 = new QTableWidgetItem("选中单元格");
item1->setSelected(true);
ui->tableWidget->setItem(3, 0, item1);

// 示例2:判断单元格是否选中
if (item1->isSelected()) {
    qDebug() << "单元格被选中了";
}

2.7 方法七:setSizeHint () & sizeHint ()------ 设置 / 获取单元格尺寸提示

这个方法和 QListWidgetItem 的 setSizeHint()/sizeHint() 几乎一模一样,我们简单回顾一下,重点讲和表格相关的注意事项。

注意! 你提供的资料里写的是 setSizeHints,这是一个笔误!Qt 官方的正确方法名是 setSizeHint(单数),没有 setSizeHints(复数)这个方法,这里我们修正过来。

2.7.1 方法的核心定义

setSizeHint() 用于为单个单元格设置固定尺寸提示,优先级高于 QTableWidget 的默认单元格尺寸;未设置时,单元格尺寸由内容(文本 + 图标)和表格列宽 / 行高自动计算。

表格相关的关键注意事项:

  1. 行列适配(超级重要!) :
    • 单元格宽度受表格列宽限制 ------ 若列宽 < size.width(),则按列宽显示;
    • 单元格高度受表格行高限制 ------ 若表格设置 setUniformRowHeights(true)(统一行高),单元格高度设置失效;
  2. 最小尺寸限制:设置的尺寸小于内容最小显示尺寸时,自动适配为内容最小尺寸。
2.7.2 使用示例
复制代码
#include <QTableWidgetItem>
#include <QSize>

// 假设表格已经设置了行列数
// 设置单元格固定尺寸(宽 150px,高 40px)
QTableWidgetItem* item = new QTableWidgetItem("自定义尺寸");
item->setSizeHint(QSize(150, 40));
ui->tableWidget->setItem(4, 0, item);

2.8 方法八:setFont () & font ()------ 设置 / 获取单元格字体样式

这个方法和 QListWidgetItem 的 setFont()/font() 几乎一模一样,我们简单回顾一下。

2.8.1 方法的核心定义

setFont() 用于自定义单个单元格的字体(大小、粗细、字体家族等),优先级高于 QTableWidget 的全局字体设置;未单独设置时,继承表格的全局字体样式。

关键注意事项:

  1. 颜色独立(超级重要!) :QFont 仅控制字体样式(大小 / 粗细 / 家族),文本颜色需通过 setForeground() 设置,不是 setFont()!
  2. 优先级:单个单元格字体 > 表格全局字体 > 应用程序默认字体;
  3. 动态生效:设置后立即刷新单元格视觉效果。
2.8.2 使用示例
复制代码
#include <QTableWidgetItem>
#include <QFont>
#include <QGuiApplication> //  Qt::red 等颜色定义

// 假设表格已经设置了行列数
// 设置单元格字体(微软雅黑、14号、粗体)
QTableWidgetItem* item = new QTableWidgetItem("自定义字体");
QFont font("Microsoft YaHei", 14, QFont::Bold);
item->setFont(font);
// 额外设置文本颜色(QFont 不包含颜色,需通过 setForeground)
item->setForeground(Qt::blue);
ui->tableWidget->setItem(4, 1, item);

示例代码:

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //OK大家,在我们前面学习完了QListWidget控件之后,我们知道,它的本质就是一个一维数组
    //一个简单的列表,每一个条目都要占一行,那么有一维数组,自然就有二维数组
    //所以接下来,我们要学习QTableWidget控件
    //这个控件其实是和QListWidget控件差不多的,只不过它能支持我们设置条目在某行某列
    //说白了其实也就是一个二维数组罢了~~~~~

    //那么一样的,QTableWidget也有自己的条目类,那就是QTableWidgetItem类
    //其实它的属性和QListWidgetItem类可以说是一模一样的,所以呢,我们就能轻而易举的学习
    //相比而言,就多了一个column罢了,用它获取所在列数

    /**
     * @class QTableWidgetItem
     * @brief Qt中QTableWidget表格控件的单元格条目类,表征表格中的单个单元格
     * @details QTableWidgetItem是QTableWidget的最小组成单元,对应表格中"行+列"定位的单个单元格;
     *          核心支持行/列位置查询、文本/图标/字体/对齐方式/尺寸/选中状态的自定义配置,是表格单元格视觉与状态定制的核心类。
     *
     * 【核心特征】
     * 1. 位置定位:可查询单元格所属的行/列号(未加入表格时返回-1);
     * 2. 视觉定制:支持文本、图标、字体、对齐方式、尺寸的个性化设置;
     * 3. 状态控制:支持选中状态的手动设置,适配表格的单选/多选交互场景。
     */

    // ============================== 核心方法详解 ==============================

    /**
     * @fn int QTableWidgetItem::row() const
     * @brief 获取当前单元格条目所属的**行号**
     * @details 核心位置查询方法,返回该条目在QTableWidget中的行索引,行号从0开始计数;
     *          若条目未添加到表格中,返回值为-1。
     *
     * @返回值说明:
     * @return int - 单元格行号(0开始,未加入表格返回-1)。
     *
     * @使用示例:
     * // 获取指定单元格的行号
     * QTableWidgetItem* item = ui->tableWidget->item(1, 2); // 获取第2行第3列单元格
     * if (item) {
     *     int rowNum = item->row();
     *     qDebug() << "单元格行号:" << rowNum; // 输出:1
     * }
     *
     * 【关键注意事项】
     * 1. 行号规则:行号从0开始,第一行=0、第二行=1,以此类推;
     * 2. 未加入表格:条目创建后未通过setItem()添加到表格时,返回-1;
     * 3. 位置联动:条目添加到表格后,行号随表格行增删(如删除上方行)自动更新。
     */

    /**
     * @fn int QTableWidgetItem::column() const
     * @brief 获取当前单元格条目所属的**列号**
     * @details 核心位置查询方法,返回该条目在QTableWidget中的列索引,列号从0开始计数;
     *          若条目未添加到表格中,返回值为-1。
     *
     * @返回值说明:
     * @return int - 单元格列号(0开始,未加入表格返回-1)。
     *
     * @使用示例:
     * // 遍历表格第一行,打印每个单元格的列号
     * for (int col = 0; col < ui->tableWidget->columnCount(); ++col) {
     *     QTableWidgetItem* item = ui->tableWidget->item(0, col);
     *     if (item) {
     *         qDebug() << "列号:" << item->column() << ",文本:" << item->text();
     *     }
     * }
     *
     * 【关键注意事项】
     * 1. 列号规则:列号从0开始,第一列=0、第二列=1,以此类推;
     * 2. 未加入表格:条目未添加到表格时返回-1,与row()规则一致;
     * 3. 位置联动:列号随表格列增删(如删除左侧列)自动更新。
     */

    /**
     * @fn void QTableWidgetItem::setText(const QString& text)
     * @brief 设置单元格的显示文本
     * @details 单元格核心内容配置方法,支持普通字符串、HTML富文本格式;
     *          文本是单元格的核心展示内容,未设置时单元格显示为空。
     *
     * @参数说明:
     * @param text - QString类型,单元格要显示的文本内容(支持UTF-8编码,可包含中文、特殊字符)。
     *
     * @使用示例:
     * // 1. 设置普通文本
     * QTableWidgetItem* item1 = new QTableWidgetItem();
     * item1->setText("普通文本单元格");
     * ui->tableWidget->setItem(0, 0, item1);
     *
     * // 2. 设置富文本(红色加粗)
     * QTableWidgetItem* item2 = new QTableWidgetItem();
     * item2->setText("<font color='red'><b>富文本单元格</b></font>");
     * ui->tableWidget->setItem(0, 1, item2);
     *
     * 【关键注意事项】
     * 1. 富文本支持:仅基础HTML标签(<b>/<i>/<font>/<br>等),复杂标签可能无法正常渲染;
     * 2. 文本截断:文本过长时,表格会自动截断并显示省略号,可通过setSizeHint扩大单元格尺寸避免;
     * 3. 编码适配:确保文本为UTF-8编码,避免中文乱码(Qt默认支持,需注意文件编码格式)。
     */

    /**
     * @fn void QTableWidgetItem::setTextAlignment(int alignment)
     * @brief 设置单元格文本的对齐方式
     * @details 控制文本在单元格内部的水平+垂直对齐位置,默认对齐方式为Qt::AlignLeft | Qt::AlignVCenter;
     *          对齐效果需结合单元格尺寸(setSizeHint)才能明显体现。
     *
     * 【核心对齐枚举值(Qt::Alignment)】
     * | 枚举值                | 功能说明                                                                 |
     * |-----------------------|--------------------------------------------------------------------------|
     * | Qt::AlignLeft         | 水平左对齐(默认);                                                     |
     * | Qt::AlignRight        | 水平右对齐;                                                             |
     * | Qt::AlignHCenter      | 水平居中;                                                               |
     * | Qt::AlignCenter       | 水平+垂直居中(等价于AlignHCenter | AlignVCenter);                     |
     * | Qt::AlignTop          | 垂直顶部对齐;                                                           |
     * | Qt::AlignBottom       | 垂直底部对齐;                                                           |
     * | Qt::AlignVCenter      | 垂直居中(默认);                                                       |
     *
     * @参数说明:
     * @param alignment - int类型,可组合多个Qt::Alignment枚举值(用|连接)。
     *
     * @使用示例:
     * // 设置单元格文本水平+垂直居中
     * QTableWidgetItem* item = new QTableWidgetItem("居中对齐");
     * item->setTextAlignment(Qt::AlignCenter);
     * item->setSizeHint(QSize(100, 50)); // 扩大单元格尺寸,对齐效果更明显
     * ui->tableWidget->setItem(1, 0, item);
     *
     * // 设置文本右对齐+垂直底部对齐
     * QTableWidgetItem* item2 = new QTableWidgetItem("右底对齐");
     * item2->setTextAlignment(Qt::AlignRight | Qt::AlignBottom);
     * ui->tableWidget->setItem(1, 1, item2);
     *
     * 【关键注意事项】
     * 1. 组合使用:对齐方式可通过|组合(如Qt::AlignHCenter | Qt::AlignTop);
     * 2. 尺寸影响:单元格尺寸过小时,对齐效果不明显,需配合setSizeHint调整;
     * 3. 图标兼容:图标始终显示在文本左侧,不受文本对齐方式影响。
     */

    /**
     * @fn void QTableWidgetItem::setIcon(const QIcon& icon)
     * @brief 设置单元格的显示图标
     * @details 为单元格添加/修改图标,图标默认显示在文本左侧,是实现"图标+文本"单元格的核心方法;
     *          未设置时单元格仅显示文本,无图标。
     *
     * @参数说明:
     * @param icon - QIcon类型,支持本地图片、资源文件、系统图标等多种图标来源。
     *
     * @使用示例:
     * // 1. 使用资源文件图标
     * QTableWidgetItem* item1 = new QTableWidgetItem("资源图标");
     * item1->setIcon(QIcon(":/images/icon.png"));
     * ui->tableWidget->setItem(2, 0, item1);
     *
     * // 2. 使用系统图标
     * QTableWidgetItem* item2 = new QTableWidgetItem("系统图标");
     * item2->setIcon(QApplication::style()->standardIcon(QStyle::SP_FileIcon));
     * ui->tableWidget->setItem(2, 1, item2);
     *
     * // 设置表格内所有图标的统一显示尺寸
     * ui->tableWidget->setIconSize(QSize(24, 24));
     *
     * 【关键注意事项】
     * 1. 尺寸控制:图标显示尺寸由QTableWidget::setIconSize()全局控制,单个单元格无法单独设置;
     * 2. 资源路径:使用资源文件时需确保路径正确(以:/开头),本地图片需传入完整路径;
     * 3. 透明适配:QIcon自动适配单元格选中/未选中状态,也可通过QIcon::addPixmap()自定义状态图标。
     */

    /**
     * @fn void QTableWidgetItem::setSelected(bool selected)
     * @brief 设置单元格是否被选中
     * @details 控制单元格的选中状态,选中的单元格会按照系统/自定义样式高亮显示;
     *          选中效果受QTableWidget的选择模式(setSelectionMode)控制。
     *
     * @参数说明:
     * @param selected - bool类型,true=选中单元格,false=取消选中(默认)。
     *
     * @使用示例:
     * // 1. 设置表格为单选模式,选中指定单元格
     * ui->tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
     * QTableWidgetItem* item1 = new QTableWidgetItem("选中单元格");
     * item1->setSelected(true);
     * ui->tableWidget->setItem(3, 0, item1);
     *
     * // 2. 多选模式下选中多个单元格
     * ui->tableWidget->setSelectionMode(QAbstractItemView::MultiSelection);
     * QTableWidgetItem* item2 = ui->tableWidget->item(3, 1);
     * if (item2) item2->setSelected(true);
     *
     * 【关键注意事项】
     * 1. 选择模式:仅在非"NoSelection"模式下,选中状态才会生效;
     * 2. 信号触发:调用setSelected()会触发QTableWidget::itemSelectionChanged()信号;
     * 3. 视觉样式:选中高亮样式可通过QSS自定义(如QTableWidget::item:selected);
     * 4. 整行/列选中:若表格开启setSelectionBehavior(QAbstractItemView::SelectRows),选中单元格会同步选中整行。
     */

    /**
     * @fn void QTableWidgetItem::setSizeHint(const QSize& size)
     * @brief 设置单元格的尺寸提示(自定义单元格大小)
     * @details 为单个单元格设置固定尺寸,优先级高于QTableWidget的默认单元格尺寸;
     *          未设置时,单元格尺寸由内容(文本+图标)和表格列宽/行高自动计算。
     * @note 注:方法名正确为setSizeHint(非setSizeHints),Qt官方无setSizeHints方法,此处为笔误修正。
     *
     * @参数说明:
     * @param size - QSize类型,width为单元格宽度,height为单元格高度(单位:像素)。
     *
     * @使用示例:
     * // 设置单元格固定尺寸(宽150px,高40px)
     * QTableWidgetItem* item = new QTableWidgetItem("自定义尺寸");
     * item->setSizeHint(QSize(150, 40));
     * ui->tableWidget->setItem(4, 0, item);
     *
     * 【关键注意事项】
     * 1. 行列适配:单元格宽度受表格列宽限制(若列宽<size.width(),则按列宽显示);
     * 2. 统一尺寸:若表格设置setUniformRowHeights(true),行高会统一,单元格高度设置失效;
     * 3. 最小尺寸:设置的尺寸小于内容最小显示尺寸时,自动适配为内容最小尺寸。
     */

    /**
     * @fn void QTableWidgetItem::setFont(const QFont& font)
     * @brief 设置单元格文本的字体样式
     * @details 自定义单个单元格的字体(大小、粗细、字体家族、颜色等),优先级高于QTableWidget的全局字体设置;
     *          未单独设置时,继承表格的全局字体样式。
     *
     * @参数说明:
     * @param font - QFont类型,包含字体家族、大小、粗细、下划线等样式属性。
     *
     * @使用示例:
     * // 设置单元格字体(微软雅黑、14号、粗体)
     * QTableWidgetItem* item = new QTableWidgetItem("自定义字体");
     * QFont font("Microsoft YaHei", 14, QFont::Bold);
     * item->setFont(font);
     * // 额外设置文本颜色(QFont不包含颜色,需通过setForeground)
     * item->setForeground(Qt::blue);
     * ui->tableWidget->setItem(4, 1, item);
     *
     * 【关键注意事项】
     * 1. 颜色独立:QFont仅控制字体样式(大小/粗细/家族),文本颜色需通过setForeground()设置;
     * 2. 优先级:单个单元格字体 > 表格全局字体 > 应用程序默认字体;
     * 3. 动态生效:设置后立即刷新单元格视觉效果,无需额外刷新表格。
     */

}

Widget::~Widget()
{
    delete ui;
}

第三章 QTableWidget 核心方法详解

讲完了 QTableWidgetItem 类,我们接下来讲 QTableWidget 的核心方法 ------ 这是操作表格单元格、行列、表头最核心的接口。我们讲:item、setItem、currentItem、currentRow、currentColumn、row、column、rowCount、columnCount、insertRow、insertColumn、removeRow、removeColumn、setHorizontalHeaderItem、setVerticalHeaderItem。


3.1 方法一:item ()------ 按行号 + 列号精准获取指定单元格

3.1.1 方法的核心定义

item() 是 QTableWidget 最核心、最常用 的单元格查询方法 ------ 它按 "行号 + 列号" 精准定位,返回表格中 "第 row 行、第 column 列" 对应的 QTableWidgetItem 指针;行 / 列号超出有效范围或该位置无单元格时,返回 nullptr。

通俗理解:item() 就像 "按坐标找格子"------ 你告诉它 "第几行、第几列",它就把那个小格子拿给你;如果坐标不对,或者那个格子是空的,它就拿个空的给你(返回 nullptr)。

这里有几个超级重要的规则,必须牢记,刻在脑子里:

  1. 行 / 列规则(超级重要!) :
    • 行号、列号均从 0 开始;
    • 有效范围:0 ≤ row < rowCount(),0 ≤ column < columnCount();
  2. 判空强制!(超级重要!说三遍!) :
    • 未设置单元格的位置会返回 nullptr;
    • 必须先判空再操作! 直接操作会导致程序崩溃!
  3. 只读指针(超级重要!) :
    • 返回的指针可修改单元格属性(如 setText);
    • 但不可手动 delete !需通过 removeRow/removeColumn 移除,或由表格自动管理!
3.1.2 关联 API 详解(逐词逐句,零模糊)
1. 按行号 + 列号获取指定单元格:QTableWidgetItem* item (int row, int column) const

函数原型:

复制代码
QTableWidgetItem* QTableWidget::item(int row, int column) const;

逐词逐句底层解析:

  • QTableWidgetItem*:返回值类型,返回单元格指针;
  • QTableWidget:::成员函数;
  • item():函数名,"获取单元格" 的意思;
  • int row:入参,目标单元格的行号;
  • int column:入参,目标单元格的列号;
  • const:常成员函数。

参数说明:

  • row:目标单元格的行号,int 类型,从 0 开始;
  • column:目标单元格的列号,int 类型,从 0 开始。

返回值说明:

  • 返回 QTableWidgetItem* 类型的指针;
  • 行 / 列有效且该位置有单元格 → 返回对应指针;
  • 行 / 列无效或该位置无单元格 → 返回 nullptr;
  • 必须先判空再操作!
3.1.3 使用示例
复制代码
#include <QTableWidgetItem>
#include <QDebug>

// 假设表格已经设置了 3 行 3 列,并填充了数据
// 获取第 2 行(索引 1)、第 3 列(索引 2)的单元格
QTableWidgetItem* targetItem = ui->tableWidget->item(1, 2);
if (targetItem != nullptr) { // 必须判空!
    qDebug() << "单元格文本:" << targetItem->text();
    // 修改文本
    targetItem->setText("已修改");
} else {
    qDebug() << "该位置无单元格";
}
3.1.4 关键注意事项(必知!)
  1. 行 / 列从 0 开始!(超级重要!);
  2. 判空强制!(超级重要!说三遍!):必须先判空再操作!
  3. 不可手动 delete 返回的指针!(超级重要!):需通过 removeRow/removeColumn 移除!

3.2 方法二:setItem ()------ 按行号 + 列号设置指定位置的单元格

3.2.1 方法的核心定义

setItem() 是 QTableWidget 最核心、最常用的单元格设置方法 ------ 它将自定义的 QTableWidgetItem 对象绑定到表格的 "第 row 行、第 column 列" 位置;若该位置已有单元格,会被新单元格覆盖。

注意! 你提供的资料里写的参数类型是 QTableWidget*,这是一个严重的笔误!正确的参数类型是 QTableWidgetItem*,这里我们修正过来。

通俗理解:setItem() 就像 "把一个准备好的小格子放到表格的指定位置"------ 你告诉它 "放到第几行、第几列",它就把小格子放进去;如果那个位置已经有小格子了,新的就会把旧的换掉。

这里有几个超级重要的规则,必须牢记,刻在脑子里:

  1. 开篇的注意事项再强调一遍!(超级重要!) :
    • 在插入条目之前,必须先指明表格的行列数量才行!
    • 可以用 setRowCount()/setColumnCount() 设置,也可以用 insertRow()/insertColumn() 插入;
    • 否则,设置的单元格可能无效,界面上看不到!
  2. 内存管理!(超级重要!说三遍!) :
    • 设置新单元格后,原单元格不会自动释放 ,需手动 delete 避免内存泄漏(如 delete ui->tableWidget->item(row, column));
    • 新单元格的所有权移交至表格,无需手动 delete(移除时用 removeRow/removeColumn);
  3. 行 / 列范围(超级重要!) :
    • 行 / 列号超出当前表格范围时,需先插入对应行列(insertRow/insertColumn),否则设置无效;
  4. 空值处理 :传入 nullptr 则清空该位置单元格。
3.2.2 关联 API 详解(逐词逐句,零模糊)
1. 按行号 + 列号设置指定位置的单元格:void setItem (int row, int column, QTableWidgetItem* item)

函数原型:

复制代码
void QTableWidget::setItem(int row, int column, QTableWidgetItem* item);

逐词逐句底层解析:

  • void:无返回值;
  • QTableWidget:::成员函数;
  • setItem():函数名,"设置单元格" 的意思;
  • int row:入参,目标位置的行号;
  • int column:入参,目标位置的列号;
  • QTableWidgetItem* item:入参,要设置的单元格对象指针。

参数说明:

  • row:目标位置的行号,int 类型,从 0 开始;
  • column:目标位置的列号,int 类型,从 0 开始;
  • item:要设置的单元格对象指针,QTableWidgetItem* 类型;
    • 必须是 new 出来的堆对象;
    • 传入 nullptr 则清空该位置单元格。
3.2.3 使用示例
复制代码
#include <QTableWidgetItem>

// 【必须!】第一步:先设置表格的行列数量!
ui->tableWidget->setRowCount(2);    // 2 行
ui->tableWidget->setColumnCount(2); // 2 列

// 第二步:设置单元格
// 示例1:为第 1 行第 1 列(索引 0,0)设置普通文本单元格
QTableWidgetItem* cellItem = new QTableWidgetItem("表格单元格");
ui->tableWidget->setItem(0, 0, cellItem);

// 示例2:为第 1 行第 2 列(索引 0,1)设置带图标的单元格
QTableWidgetItem* iconItem = new QTableWidgetItem("带图标单元格");
iconItem->setIcon(QIcon(":/images/icon.png"));
ui->tableWidget->setItem(0, 1, iconItem);
3.2.4 关键注意事项(必知!)
  1. 必须先设置表格的行列数量!(超级重要!开篇就讲!);
  2. 内存管理!(超级重要!说三遍!):设置新单元格前,原单元格需手动 delete!新单元格所有权移交表格!
  3. 行 / 列范围(超级重要!):超出范围需先插入行列!
  4. 参数类型修正:是 QTableWidgetItem*,不是 QTableWidget*!

3.3 方法三:currentItem ()------ 获取当前选中的单元格对象

3.3.1 方法的核心定义

currentItem() 是 QTableWidget 用于获取当前选中单元格对象指针 的核心方法 ------ 无选中单元格 / 表格为空时返回 nullptr,是操作选中单元格属性的核心入口。

通俗理解:currentItem() 就像 "拿到表格上当前被标亮的那个小格子"------ 拿到后你就可以读它、改它;如果没有任何格子被标亮,或者表格是空的,你就拿不到(返回 nullptr)。

这里有几个超级重要的规则,必须牢记:

  1. 判空必须!(超级重要!说三遍!) :
    • 无选中单元格 / 表格为空时返回 nullptr;
    • 必须先判空再操作! 直接操作会导致程序崩溃!
  2. 受选择模式影响 :若表格设为 NoSelection(无选择),始终返回 nullptr;
  3. 联动查询 :可结合 currentRow()/currentColumn() 快速获取选中单元格的位置。
3.3.2 使用示例
复制代码
#include <QTableWidgetItem>
#include <QDebug>

// 获取选中单元格并操作(必须先判空!)
QTableWidgetItem* selectedItem = ui->tableWidget->currentItem();
if (selectedItem != nullptr) { // 判空!判空!判空!
    qDebug() << "当前选中单元格文本:" << selectedItem->text();
    selectedItem->setText("已选中:" + selectedItem->text());
} else {
    qDebug() << "当前无选中单元格";
}

3.4 方法四:currentRow ()------ 获取当前选中单元格所属的行号

3.4.1 方法的核心定义

currentRow() 是 QTableWidget 用于获取当前选中单元格所属行号的方法 ------ 行号从 0 开始;无选中单元格时返回 -1。

通俗理解:currentRow() 就像 "问表格:'当前被标亮的格子在第几行呀?'"------ 它会告诉你行号,从 0 开始;如果没有被标亮的格子,它就说 -1。

关键注意事项:

  1. 行号从 0 开始!(超级重要!):用户视角展示需 +1;
  2. 联动关系 :currentRow() = currentItem()->row()(currentItem 不为 nullptr 时);
  3. 整行选中 :若表格开启 setSelectionBehavior(SelectRows),选中任意单元格均返回该行号。
3.4.2 使用示例
复制代码
#include <QDebug>

// 打印当前选中单元格的行号和列号
int selRow = ui->tableWidget->currentRow();
int selCol = ui->tableWidget->currentColumn();
if (selRow != -1 && selCol != -1) {
    qDebug() << "选中位置:第" << selRow+1 << "行,第" << selCol+1 << "列";
} else {
    qDebug() << "无选中单元格";
}

3.5 方法五:currentColumn ()------ 获取当前选中单元格所属的列号

这个方法和 currentRow() 几乎一模一样,只是返回的是列号,我们简单回顾一下。

关键注意事项:

  1. 列号从 0 开始!(超级重要!):用户视角展示需 +1;
  2. 联动关系 :currentColumn() = currentItem()->column()(currentItem 不为 nullptr 时);
  3. 整列选中 :若表格开启 setSelectionBehavior(SelectColumns),选中任意单元格均返回该列号。

3.6 方法六:row ()------ 根据单元格对象获取其所属的行号

这个方法我们在讲 QTableWidgetItem::row () 时已经提到过,它和 item->row() 是等价的,结果完全一致。

通俗理解:table->row(item) 就像 "你拿着一个小格子问表格:'这个格子在你这里的第几行呀?'"------ 和直接问格子自己是一样的。


3.7 方法七:column ()------ 根据单元格对象获取其所属的列号

这个方法和 table->row(item) 几乎一模一样,只是返回的是列号,它和 item->column() 是等价的。


3.8 方法八:rowCount ()------ 获取表格当前的总行数

3.8.1 方法的核心定义

rowCount() 是 QTableWidget 用于获取表格当前总行数的结构查询方法 ------ 返回表格中已存在的行总数(包含空行),默认值为 0(空表格)。

通俗理解:rowCount() 就像 "数一数表格里一共有多少行"------ 哪怕某一行是空的,没有任何单元格,也算一行。

关键注意事项:

  1. 实时更新 :插入 / 删除行(insertRow/removeRow)后,rowCount() 立即更新;
  2. 空行计数:即使行内无单元格(空行),仍计入总行数;
  3. 遍历边界 :遍历行时,循环上限为 rowCount()-1。
3.8.2 使用示例
复制代码
#include <QTableWidgetItem>
#include <QDebug>

// 遍历表格所有行
int totalRows = ui->tableWidget->rowCount();
for (int r = 0; r < totalRows; ++r) {
    // 处理每行数据,比如获取每行第一列的文本
    QTableWidgetItem* firstCell = ui->tableWidget->item(r, 0);
    if (firstCell != nullptr) {
        qDebug() << "第" << r+1 << "行首列文本:" << firstCell->text();
    }
}

3.9 方法九:columnCount ()------ 获取表格当前的总列数

这个方法和 rowCount() 几乎一模一样,只是返回的是总列数,我们简单回顾一下。

关键注意事项:

  1. 实时更新 :插入 / 删除列(insertColumn/removeColumn)后,columnCount() 立即更新;
  2. 空列计数:即使列内无单元格(空列),仍计入总列数;
  3. 遍历边界 :遍历列时,循环上限为 columnCount()-1。

3.10 方法十:insertRow ()------ 在指定行号位置插入新行

3.10.1 方法的核心定义

insertRow() 是 QTableWidget 用于扩展表格行数 的方法 ------ 它在第 row 行位置插入一行空行;row 超出当前行号范围时,自动追加到表格末尾。

通俗理解:insertRow() 就像 "在表格的指定位置插入一行新的空白行"------ 比如在第 2 行(行号 1)前面插一行,原来的第 2 行及后面的行都会自动往后挪一位。

这里有几个超级重要的规则,必须牢记:

  1. 行号容错(超级重要!) :
    • row < 0 → 插入到开头(行号 0);
    • row > rowCount() → 追加到末尾(等价于在最后添加一行);
    • 不用担心行号超出范围,Qt 会自动适配!
  2. 行号偏移(超级重要!) :
    • 插入位置后的行号自动 +1;
    • 比如在索引 1 插入,原索引 1 行变为索引 2,原索引 2 变为索引 3,以此类推;
  3. 空行特性 :插入的新行为空行,需手动调用 setItem() 设置单元格。
3.10.2 使用示例
复制代码
#include <QTableWidgetItem>

// 示例1:在第 1 行(索引 0)插入新行
ui->tableWidget->insertRow(0);
// 为新插入的行设置单元格
QTableWidgetItem* newItem = new QTableWidgetItem("新行首列");
ui->tableWidget->setItem(0, 0, newItem);

// 示例2:在表格末尾插入新行(常用!)
int lastRow = ui->tableWidget->rowCount();
ui->tableWidget->insertRow(lastRow);

3.11 方法十一:insertColumn ()------ 在指定列号位置插入新列

这个方法和 insertRow() 几乎一模一样,只是操作的是列,我们简单回顾一下。

关键注意事项:

  1. 列号容错(超级重要!) :
    • column < 0 → 插入到开头(列号 0);
    • column > columnCount() → 追加到末尾;
  2. 列号偏移(超级重要!) :
    • 插入位置后的列号自动 +1;
  3. 空列特性 :插入的新列为空列,需手动调用 setItem() 设置单元格。

3.12 方法十二:removeRow ()------ 删除指定行号的整行

3.12.1 方法的核心定义

removeRow() 是 QTableWidget 用于删除表格整行 的方法 ------ 它删除第 row 行的所有单元格并移除该行;row 超出有效范围时无操作。

通俗理解:removeRow() 就像 "把表格的指定行整行撕掉"------ 撕掉后,这一行的所有小格子都会被扔掉(自动释放内存),后面的行会自动往前挪填补位置。

这里有几个超级重要的规则,必须牢记,刻在脑子里:

  1. 内存释放!(超级重要!说三遍!) :
    • 删除行时,该行所有 QTableWidgetItem 会被自动释放!
    • 无需手动 delete !不要去 delete 该行的单元格!
    • 这点和 QListWidget 的 takeItem() 不一样!
  2. 行号偏移(超级重要!) :
    • 删除位置后的行号自动 -1;
    • 比如删除索引 1 行,原索引 2 行变为索引 1,原索引 3 变为索引 2,以此类推;
  3. 选中状态(超级重要!) :
    • 若删除的是选中行,currentRow() 变为 -1,取消选中。
3.12.2 使用示例
复制代码
// 示例1:删除表格第 2 行(索引 1)
if (ui->tableWidget->rowCount() > 1) { // 确保行号有效
    ui->tableWidget->removeRow(1);
}

// 示例2:删除表格最后一行(常用!)
if (ui->tableWidget->rowCount() > 0) {
    int lastRow = ui->tableWidget->rowCount() - 1;
    ui->tableWidget->removeRow(lastRow);
}

3.13 方法十三:removeColumn ()------ 删除指定列号的整列

这个方法和 removeRow() 几乎一模一样,只是操作的是列,我们简单回顾一下。

关键注意事项:

  1. 内存释放!(超级重要!):删除列时,该列所有 QTableWidgetItem 会被自动释放,无需手动 delete!
  2. 列号偏移(超级重要!):删除位置后的列号自动 -1;
  3. 选中状态(超级重要!) :若删除的是选中列,currentColumn() 变为 -1,取消选中。

3.14 方法十四:setHorizontalHeaderItem ()------ 设置水平表头(列标题)

3.14.1 方法的核心定义

setHorizontalHeaderItem() 是 QTableWidget 用于 ** 定制水平表头(列标题)** 的方法 ------ 它为第 column 列的水平表头设置自定义条目(文本 / 图标 / 字体);水平表头默认显示列号(1, 2, 3...),设置后替换为自定义内容。

通俗理解:setHorizontalHeaderItem() 就像 "给表格的每一列起个名字"------ 比如第一列叫 "姓名",第二列叫 "年龄",第三列叫 "学号";这些名字显示在表格的最上方。

这里有几个超级重要的规则,必须牢记:

  1. 列存在性(超级重要!) :
    • column 需小于 columnCount(),否则需先调用 insertColumn() 创建列;
    • 或者先设置好 columnCount() 再设置表头;
  2. 内存管理 :item 所有权移交至表格,无需手动 delete;
  3. 样式定制 :可通过 item 的 setFont/setIcon/setTextAlignment 定制表头样式。
3.14.2 使用示例
复制代码
#include <QTableWidgetItem>
#include <QFont>
#include <QStringList>

// 【必须!】先设置表格列数(或者先插入列)
ui->tableWidget->setColumnCount(3); // 3 列

// 设置水平表头(列标题)
QStringList headers = {"姓名", "年龄", "性别"};
for (int c = 0; c < headers.size(); ++c) {
    QTableWidgetItem* headerItem = new QTableWidgetItem(headers[c]);
    // 可选:设置表头字体加粗、居中
    headerItem->setFont(QFont("微软雅黑", 12, QFont::Bold));
    headerItem->setTextAlignment(Qt::AlignCenter);
    ui->tableWidget->setHorizontalHeaderItem(c, headerItem);
}

3.15 方法十五:setVerticalHeaderItem ()------ 设置垂直表头(行标题)

这个方法和 setHorizontalHeaderItem() 几乎一模一样,只是操作的是垂直表头(行标题),显示在表格的最左侧,默认显示行号(1, 2, 3...)。

关键注意事项:

  1. 行存在性(超级重要!) :row 需小于 rowCount(),否则需先调用 insertRow() 创建行;
  2. 内存管理 :item 所有权移交至表格,无需手动 delete;
  3. 隐藏表头 :可通过 setVerticalHeaderHidden(true) 隐藏垂直表头,通过 setHorizontalHeaderHidden(true) 隐藏水平表头。

示例代码:

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"
#include <QTableWidget>
#include <QTableWidgetItem>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //OK,那么本文件我们就来学习一下QTableWidget的核心方法,这个还是很关键的
    //无论是添加还是删除条目,都是在这其中
    //而且由于这是二维的了,我们我们不仅要指定行,还得指定列哦~~~
    //新增的方法名字叫做setItem~~~

    //注意,都是从0开始计数的哦,虽然qt对外显示是从1开始,但是我们要指定行列什么的,
    //就是从0开始计数的哦~~~~

    //其实还是比较简单的~~~

    /**
     * @class QTableWidget
     * @brief Qt中用于展示二维表格的可视化控件,基于QTableWidgetItem管理单元格、行列、表头
     * @details QTableWidget以"行+列"二维结构组织单元格(QTableWidgetItem),提供单元格/行列的增删改查、选中状态查询、表头定制等核心功能;
     *          支持精准定位单元格、动态插入/删除行列、自定义表头样式,是Qt中最常用的表格展示与交互控件之一。
     *
     * 【核心特征】
     * 1. 单元格管理:支持按行/列号精准获取/设置单元格,查询选中单元格的位置与对象;
     * 2. 行列管理:支持获取行列总数、插入/删除指定行列,动态调整表格结构;
     * 3. 表头定制:支持自定义水平(列)/垂直(行)表头的显示内容;
     * 4. 选中查询:支持获取当前选中单元格的对象、行号、列号,适配表格交互场景。
     */

    // ============================== 核心方法详解 ==============================

    /**
     * @fn QTableWidgetItem* QTableWidget::item(int row, int column) const
     * @brief 按行号+列号精准获取指定单元格的条目指针
     * @details 核心单元格查询方法,返回表格中"第row行、第column列"对应的QTableWidgetItem指针;
     *          行/列号超出有效范围或该位置无单元格时,返回nullptr。
     *
     * @参数说明:
     * @param row - int类型,目标单元格的行号(从0开始计数);
     * @param column - int类型,目标单元格的列号(从0开始计数)。
     *
     * @返回值说明:
     * @return QTableWidgetItem* - 指定位置的单元格指针(行/列无效/无单元格返回nullptr)。
     *
     * @使用示例:
     * // 获取第2行(索引1)、第3列(索引2)的单元格
     * QTableWidgetItem* targetItem = ui->tableWidget->item(1, 2);
     * if (targetItem) { // 必须判空,避免空指针崩溃
     *     qDebug() << "单元格文本:" << targetItem->text();
     * }
     *
     * 【关键注意事项】
     * 1. 行/列规则:行号、列号均从0开始,有效范围为[0, rowCount()-1]、[0, columnCount()-1];
     * 2. 判空强制:未设置单元格的位置会返回nullptr,直接操作会导致程序崩溃;
     * 3. 只读指针:返回的指针可修改单元格属性(如setText),但不可手动delete(需通过removeRow/removeColumn移除)。
     */

    /**
     * @fn void QTableWidget::setItem(int row, int column, QTableWidgetItem* item)
     * @brief 按行号+列号设置表格中指定位置的单元格
     * @details 核心单元格设置方法,将自定义的QTableWidgetItem对象绑定到表格的"第row行、第column列"位置;
     *          若该位置已有单元格,会被新单元格覆盖(原单元格需手动释放内存避免泄漏)。
     * @note 注:方法参数正确类型为QTableWidgetItem*(非QTableWidget*),此处修正笔误。
     *
     * @参数说明:
     * @param row - int类型,目标位置的行号(从0开始计数);
     * @param column - int类型,目标位置的列号(从0开始计数);
     * @param item - QTableWidgetItem*类型,要设置的单元格对象(nullptr则清空该位置单元格)。
     *
     * @使用示例:
     * // 1. 为第1行第1列设置普通文本单元格
     * QTableWidgetItem* cellItem = new QTableWidgetItem("表格单元格");
     * ui->tableWidget->setItem(0, 0, cellItem);
     *
     * // 2. 为第1行第2列设置带图标的单元格
     * QTableWidgetItem* iconItem = new QTableWidgetItem("带图标单元格");
     * iconItem->setIcon(QIcon(":/images/icon.png"));
     * ui->tableWidget->setItem(0, 1, iconItem);
     *
     * 【关键注意事项】
     * 1. 内存管理:设置新单元格后,原单元格不会自动释放,需手动delete(如delete ui->tableWidget->item(row, column));
     * 2. 行/列范围:行/列号超出当前表格范围时,需先插入对应行列(insertRow/insertColumn),否则设置无效;
     * 3. 所有权移交:item的所有权移交至表格,无需手动delete(移除时用removeRow/removeColumn)。
     */

    /**
     * @fn QTableWidgetItem* QTableWidget::currentItem() const
     * @brief 获取当前**选中**的单元格条目指针
     * @details 核心选中状态查询方法,返回表格中当前激活选中的单元格指针;无选中单元格/表格为空时返回nullptr。
     *
     * @返回值说明:
     * @return QTableWidgetItem* - 当前选中单元格指针(无选中返回nullptr)。
     *
     * @使用示例:
     * // 获取选中单元格并修改其文本
     * QTableWidgetItem* selectedItem = ui->tableWidget->currentItem();
     * if (selectedItem) {
     *     selectedItem->setText("已选中:" + selectedItem->text());
     * }
     *
     * 【关键注意事项】
     * 1. 判空必须:无选中单元格时返回nullptr,直接操作会导致崩溃;
     * 2. 选中模式:受表格选择模式(setSelectionMode)影响,无选择权限时始终返回nullptr;
     * 3. 联动查询:可结合currentRow()/currentColumn()快速获取选中单元格的位置。
     */

    /**
     * @fn int QTableWidget::currentRow() const
     * @brief 获取当前**选中**单元格所属的行号
     * @details 选中位置查询方法,返回当前选中单元格的行号(从0开始);无选中单元格时返回-1。
     *
     * @返回值说明:
     * @return int - 选中单元格行号(0开始,无选中返回-1)。
     *
     * @使用示例:
     * // 打印当前选中单元格的行号和列号
     * int selRow = ui->tableWidget->currentRow();
     * int selCol = ui->tableWidget->currentColumn();
     * if (selRow != -1 && selCol != -1) {
     *     qDebug() << "选中位置:第" << selRow+1 << "行,第" << selCol+1 << "列";
     * } else {
     *     qDebug() << "无选中单元格";
     * }
     *
     * 【关键注意事项】
     * 1. 行号规则:行号从0开始,用户视角展示需+1;
     * 2. 联动关系:currentRow() = currentItem()->row()(currentItem不为nullptr时);
     * 3. 整行选中:若表格开启整行选中(setSelectionBehavior(SelectRows)),选中任意单元格均返回该行号。
     */

    /**
     * @fn int QTableWidget::currentColumn() const
     * @brief 获取当前**选中**单元格所属的列号
     * @details 选中位置查询方法,返回当前选中单元格的列号(从0开始);无选中单元格时返回-1。
     *
     * @返回值说明:
     * @return int - 选中单元格列号(0开始,无选中返回-1)。
     *
     * @使用示例:
     * // 验证选中单元格的列号是否为目标列
     * if (ui->tableWidget->currentColumn() == 2) {
     *     qDebug() << "选中了第3列单元格";
     * }
     *
     * 【关键注意事项】
     * 1. 列号规则:列号从0开始,用户视角展示需+1;
     * 2. 联动关系:currentColumn() = currentItem()->column()(currentItem不为nullptr时);
     * 3. 整列选中:若表格开启整列选中(setSelectionBehavior(SelectColumns)),选中任意单元格均返回该列号。
     */

    /**
     * @fn int QTableWidget::row(QTableWidgetItem* item) const
     * @brief 根据单元格对象获取其所属的**行号**
     * @details 反向位置查询方法,返回指定单元格在表格中的行号;item为nullptr或未加入表格时返回-1。
     *
     * @参数说明:
     * @param item - QTableWidgetItem*类型,目标单元格对象指针。
     *
     * @返回值说明:
     * @return int - 单元格行号(0开始,无效item返回-1)。
     *
     * @使用示例:
     * // 获取指定单元格的行/列号
     * QTableWidgetItem* targetItem = ui->tableWidget->item(1, 2);
     * if (targetItem) {
     *     int row = ui->tableWidget->row(targetItem);
     *     int col = ui->tableWidget->column(targetItem);
     *     qDebug() << "单元格位置:行" << row << ",列" << col;
     * }
     *
     * 【关键注意事项】
     * 1. 等价性:table->row(item) 等价于 item->row(),二者结果一致;
     * 2. 无效判断:item为nullptr或未通过setItem()加入表格时,返回-1;
     * 3. 动态更新:单元格行号随表格行增删自动更新,该方法返回实时行号。
     */

    /**
     * @fn int QTableWidget::column(QTableWidgetItem* item) const
     * @brief 根据单元格对象获取其所属的**列号**
     * @details 反向位置查询方法,返回指定单元格在表格中的列号;item为nullptr或未加入表格时返回-1。
     *
     * @参数说明:
     * @param item - QTableWidgetItem*类型,目标单元格对象指针。
     *
     * @返回值说明:
     * @return int - 单元格列号(0开始,无效item返回-1)。
     *
     * @使用示例:
     * // 遍历表格所有单元格,打印非空单元格的位置
     * for (int r = 0; r < ui->tableWidget->rowCount(); ++r) {
     *     for (int c = 0; c < ui->tableWidget->columnCount(); ++c) {
     *         QTableWidgetItem* item = ui->tableWidget->item(r, c);
     *         if (item) {
     *             int row = ui->tableWidget->row(item);
     *             int col = ui->tableWidget->column(item);
     *             qDebug() << "非空单元格:行" << row << "列" << col << ",文本:" << item->text();
     *         }
     *     }
     * }
     *
     * 【关键注意事项】
     * 1. 等价性:table->column(item) 等价于 item->column(),二者结果一致;
     * 2. 无效判断:item为nullptr或未加入表格时,返回-1;
     * 3. 动态更新:单元格列号随表格列增删自动更新,该方法返回实时列号。
     */

    /**
     * @fn int QTableWidget::rowCount() const
     * @brief 获取表格当前的**总行数**
     * @details 表格结构查询方法,返回表格中已存在的行总数(包含空行),默认值为0(空表格)。
     *
     * @返回值说明:
     * @return int - 表格总行数(≥0)。
     *
     * @使用示例:
     * // 遍历表格所有行
     * int totalRows = ui->tableWidget->rowCount();
     * for (int r = 0; r < totalRows; ++r) {
     *     // 处理每行数据
     *     QTableWidgetItem* firstCell = ui->tableWidget->item(r, 0);
     *     if (firstCell) qDebug() << "第" << r+1 << "行首列文本:" << firstCell->text();
     * }
     *
     * 【关键注意事项】
     * 1. 实时更新:插入/删除行(insertRow/removeRow)后,rowCount()立即更新;
     * 2. 空行计数:即使行内无单元格(空行),仍计入总行数;
     * 3. 遍历边界:遍历行时,循环上限为rowCount()-1。
     */

    /**
     * @fn int QTableWidget::columnCount() const
     * @brief 获取表格当前的**总列数**
     * @details 表格结构查询方法,返回表格中已存在的列总数(包含空列),默认值为0(空表格)。
     *
     * @返回值说明:
     * @return int - 表格总列数(≥0)。
     *
     * @使用示例:
     * // 检查表格列数是否满足需求
     * if (ui->tableWidget->columnCount() < 3) {
     *     // 补充列至3列
     *     int needAdd = 3 - ui->tableWidget->columnCount();
     *     for (int i = 0; i < needAdd; ++i) {
     *         ui->tableWidget->insertColumn(ui->tableWidget->columnCount());
     *     }
     * }
     *
     * 【关键注意事项】
     * 1. 实时更新:插入/删除列(insertColumn/removeColumn)后,columnCount()立即更新;
     * 2. 空列计数:即使列内无单元格(空列),仍计入总列数;
     * 3. 遍历边界:遍历列时,循环上限为columnCount()-1。
     */

    /**
     * @fn void QTableWidget::insertRow(int row)
     * @brief 在表格指定行号位置**插入新行**
     * @details 表格行扩展方法,在第row行位置插入一行空行;row超出当前行号范围时,自动追加到表格末尾。
     *
     * @参数说明:
     * @param row - int类型,插入新行的目标位置(从0开始计数)。
     *
     * @使用示例:
     * // 在第1行(索引0)插入新行
     * ui->tableWidget->insertRow(0);
     * // 为新插入的行设置单元格
     * QTableWidgetItem* newItem = new QTableWidgetItem("新行首列");
     * ui->tableWidget->setItem(0, 0, newItem);
     *
     * 【关键注意事项】
     * 1. 行号容错:row < 0 → 插入到开头;row > rowCount() → 追加到末尾;
     * 2. 行号偏移:插入位置后的行号自动+1(如在索引1插入,原索引1行变为索引2);
     * 3. 空行特性:插入的新行为空行,需手动调用setItem()设置单元格。
     */

    /**
     * @fn void QTableWidget::insertColumn(int column)
     * @brief 在表格指定列号位置**插入新列**
     * @details 表格列扩展方法,在第column列位置插入一列空列;column超出当前列号范围时,自动追加到表格末尾。
     *
     * @参数说明:
     * @param column - int类型,插入新列的目标位置(从0开始计数)。
     *
     * @使用示例:
     * // 在表格末尾插入新列
     * int lastCol = ui->tableWidget->columnCount();
     * ui->tableWidget->insertColumn(lastCol);
     * // 设置新列的表头
     * QTableWidgetItem* headerItem = new QTableWidgetItem("新列表头");
     * ui->tableWidget->setHorizontalHeaderItem(lastCol, headerItem);
     *
     * 【关键注意事项】
     * 1. 列号容错:column < 0 → 插入到开头;column > columnCount() → 追加到末尾;
     * 2. 列号偏移:插入位置后的列号自动+1(如在索引1插入,原索引1列变为索引2);
     * 3. 空列特性:插入的新列为空列,需手动调用setItem()设置单元格。
     */

    /**
     * @fn void QTableWidget::removeRow(int row)
     * @brief 删除表格中指定行号的**整行**
     * @details 表格行删除方法,删除第row行的所有单元格并移除该行;row超出有效范围时无操作。
     *
     * @参数说明:
     * @param row - int类型,要删除的行号(从0开始计数)。
     *
     * @使用示例:
     * // 删除表格最后一行
     * if (ui->tableWidget->rowCount() > 0) {
     *     ui->tableWidget->removeRow(ui->tableWidget->rowCount() - 1);
     * }
     *
     * 【关键注意事项】
     * 1. 内存释放:删除行时,该行所有QTableWidgetItem会被自动释放,无需手动delete;
     * 2. 行号偏移:删除位置后的行号自动-1(如删除索引1行,原索引2行变为索引1);
     * 3. 选中状态:若删除的是选中行,currentRow()变为-1,取消选中。
     */

    /**
     * @fn void QTableWidget::removeColumn(int column)
     * @brief 删除表格中指定列号的**整列**
     * @details 表格列删除方法,删除第column列的所有单元格并移除该列;column超出有效范围时无操作。
     *
     * @参数说明:
     * @param column - int类型,要删除的列号(从0开始计数)。
     *
     * @使用示例:
     * // 删除表格第一列(索引0)
     * if (ui->tableWidget->columnCount() > 0) {
     *     ui->tableWidget->removeColumn(0);
     * }
     *
     * 【关键注意事项】
     * 1. 内存释放:删除列时,该列所有QTableWidgetItem会被自动释放,无需手动delete;
     * 2. 列号偏移:删除位置后的列号自动-1(如删除索引1列,原索引2列变为索引1);
     * 3. 选中状态:若删除的是选中列,currentColumn()变为-1,取消选中。
     */

    /**
     * @fn void QTableWidget::setHorizontalHeaderItem(int column, QTableWidgetItem* item)
     * @brief 设置表格**水平表头(列标题)** 的指定列条目
     * @details 表头定制方法,为第column列的水平表头设置自定义条目(文本/图标/字体);
     *          水平表头默认显示列号,设置后替换为自定义内容。
     * @note 注:方法参数正确类型为QTableWidgetItem*(非QTableWidget*),此处修正笔误。
     *
     * @参数说明:
     * @param column - int类型,要设置的表头列号(从0开始计数);
     * @param item - QTableWidgetItem*类型,表头条目对象(nullptr则清空该列表头)。
     *
     * @使用示例:
     * // 设置水平表头(列标题)
     * QStringList headers = {"姓名", "年龄", "性别"};
     * for (int c = 0; c < headers.size(); ++c) {
     *     // 确保列存在
     *     if (c >= ui->tableWidget->columnCount()) {
     *         ui->tableWidget->insertColumn(c);
     *     }
     *     QTableWidgetItem* headerItem = new QTableWidgetItem(headers[c]);
     *     headerItem->setFont(QFont("微软雅黑", 12, QFont::Bold)); // 表头字体加粗
     *     ui->tableWidget->setHorizontalHeaderItem(c, headerItem);
     * }
     *
     * 【关键注意事项】
     * 1. 列存在性:column需小于columnCount(),否则需先调用insertColumn()创建列;
     * 2. 内存管理:item所有权移交至表格,无需手动delete;
     * 3. 样式定制:可通过item的setFont/setIcon/setTextAlignment定制表头样式。
     */

    /**
     * @fn void QTableWidget::setVerticalHeaderItem(int row, QTableWidgetItem* item)
     * @brief 设置表格**垂直表头(行标题)** 的指定行条目
     * @details 表头定制方法,为第row行的垂直表头设置自定义条目(文本/图标/字体);
     *          垂直表头默认显示行号,设置后替换为自定义内容。
     * @note 注:方法参数正确类型为QTableWidgetItem*(非QTableWidget*),此处修正笔误。
     *
     * @参数说明:
     * @param row - int类型,要设置的表头行号(从0开始计数);
     * @param item - QTableWidgetItem*类型,表头条目对象(nullptr则清空该行表头)。
     *
     * @使用示例:
     * // 设置垂直表头(行标题)
     * for (int r = 0; r < 3; ++r) {
     *     // 确保行存在
     *     if (r >= ui->tableWidget->rowCount()) {
     *         ui->tableWidget->insertRow(r);
     *     }
     *     QTableWidgetItem* headerItem = new QTableWidgetItem(QString("行%1").arg(r+1));
     *     headerItem->setTextAlignment(Qt::AlignCenter); // 表头文本居中
     *     ui->tableWidget->setVerticalHeaderItem(r, headerItem);
     * }
     *
     * 【关键注意事项】
     * 1. 行存在性:row需小于rowCount(),否则需先调用insertRow()创建行;
     * 2. 内存管理:item所有权移交至表格,无需手动delete;
     * 3. 样式定制:可通过item的setFont/setIcon/setTextAlignment定制表头样式;
     * 4. 隐藏表头:可通过setVerticalHeaderHidden(true)隐藏垂直表头。
     */

    QTableWidget* tw=new QTableWidget(this);

    tw->setGeometry(100,100,300,300);

    // 2. 【必须】设置表格的行列数量
    //要严格注意,在插入条目之前,必须先指明表格的行列数量才行哦~~~
    tw->setRowCount(2);    // 2行
    tw->setColumnCount(2); // 2列

    //然后还有就是,一般在我们设置完表格的行列数量之后
    //qt就会自动在表格的上方和左方加上表头,1、2什么的
    //要是我们想自定义,那么就得使用上面提到的
    //setHorizonalHeaderItem方法和setVerticalHeaderItem方法
    //指明是横还是竖的哪一行哪一列,然后进行设置
    //注意:从0开始计数

    // ================= 设置水平表头 (列标题) =================
    // 注意:第二个参数必须是 QTableWidgetItem* 对象

    // 第 0 列 表头
    QTableWidgetItem* headerItem0 = new QTableWidgetItem("姓名");
    // 可选:设置表头文字居中
    headerItem0->setTextAlignment(Qt::AlignCenter);
    tw->setHorizontalHeaderItem(0, headerItem0);

    // 第 1 列 表头
    QTableWidgetItem* headerItem1 = new QTableWidgetItem("年龄");
    headerItem1->setTextAlignment(Qt::AlignCenter);
    tw->setHorizontalHeaderItem(1, headerItem1);

    // ================= 设置垂直表头 (行标题) =================
    // 如果你想自定义左侧的行号 (默认是 1, 2, 3...)

    // 第 0 行 表头
    QTableWidgetItem* vHeaderItem0 = new QTableWidgetItem("第一行");
    tw->setVerticalHeaderItem(0, vHeaderItem0);

    // 第 1 行 表头
    QTableWidgetItem* vHeaderItem1 = new QTableWidgetItem("第二行");
    tw->setVerticalHeaderItem(1, vHeaderItem1);


    // ================= 填充表格内容 =================
    QTableWidgetItem* item1 = new QTableWidgetItem("张三");
    QTableWidgetItem* item2 = new QTableWidgetItem("18");
    QTableWidgetItem* item3 = new QTableWidgetItem("李四");
    QTableWidgetItem* item4 = new QTableWidgetItem("20");

    // 放入表格,要指定行和列哦~~~
    tw->setItem(0, 0, item1);
    tw->setItem(0, 1, item2);
    tw->setItem(1, 0, item3);
    tw->setItem(1, 1, item4);

    //我们还可以在指定行那里增加行
    //即将原本的那一行往后赶,新增的成为那一行,列也是同理~~~

}

Widget::~Widget()
{
    delete ui;
}

第四章 QTableWidget 核心交互信号详解

讲完了所有核心方法,我们最后来讲 QTableWidget 的核心交互信号------ 这是表格与业务逻辑联动的核心桥梁,覆盖点击、双击、鼠标悬浮、选中变更等场景。

按照你提供的顺序,我们讲:cellClicked、cellDoubleClicked、cellEntered、currentCellChanged。


4.1 信号一:cellClicked (int row, int column)------ 用户鼠标单击单元格时触发

4.1.1 信号的核心定义

cellClicked 是 QTableWidget 纯交互触发 的信号 ------ 它仅响应用户鼠标单击单元格操作,代码选中单元格不触发,参数返回被点击单元格的行 / 列号(从 0 开始)。

通俗理解:cellClicked 就像 "用户用鼠标点了表格里的某个小格子时通知你"------ 它会告诉你 "点的是第几行、第几列";只响应用户的点击,你用代码选中格子它不会通知你。

这里有几个超级重要的规则,必须牢记:

  1. 触发条件(超级重要!) :
    • 仅用户单击单元格触发;
    • 代码调用 setCurrentCell() / setCurrentItem() 不触发;
    • 这点和 currentCellChanged 不一样!
  2. 参数有效性(超级重要!) :
    • row/column 始终为有效范围(0 ≤ row < rowCount(),0 ≤ column < columnCount());
    • 点击表格空白处(无单元格区域)不触发此信号;
    • 无需额外校验参数有效性!
  3. 选中联动(超级重要!) :
    • 单击单元格会自动将其设为当前选中单元格;
    • 因此会先触发 cellClicked(),再触发 currentCellChanged();
  4. 重复点击同一条目也触发(超级重要!) :
    • 哪怕单元格已经是选中项,再次点击也会触发 cellClicked()!
    • 这点和 currentCellChanged 不一样!
4.1.2 信号参数详解

信号原型:

复制代码
void QTableWidget::cellClicked(int row, int column);

参数说明:

  • row:int 类型,被点击单元格的行号(从 0 开始);
  • column:int 类型,被点击单元格的列号(从 0 开始)。
4.1.3 使用示例
复制代码
#include <QTableWidgetItem>
#include <QDebug>

// 绑定信号(用 Lambda 表达式)
connect(ui->tableWidget, &QTableWidget::cellClicked,
        this, [=](int row, int col){
    qDebug() << "单击单元格:第" << row+1 << "行,第" << col+1 << "列";
    // 获取该单元格并修改文本
    QTableWidgetItem* item = ui->tableWidget->item(row, col);
    if (item != nullptr) {
        item->setText("已单击");
    }
});

4.2 信号二:cellDoubleClicked (int row, int column)------ 用户鼠标双击单元格时触发

4.2.1 信号的核心定义

cellDoubleClicked 是 QTableWidget 适配 "双击单元格执行核心操作" 场景的信号 ------ 它仅响应用户鼠标双击操作,代码操作不触发,参数返回被双击单元格的行 / 列号。

通俗理解:cellDoubleClicked 就像 "用户用鼠标快速双击了表格里的某个小格子时通知你"------ 它适合做 "编辑单元格""打开详情""查看关联数据" 这种需要双击确认的操作。

这里有几个超级重要的规则,必须牢记:

  1. 触发顺序(超级重要!) :
    • 双击会先触发 cellClicked()(第一次单击),再触发此信号;
    • 如果你同时绑定了这两个信号,要注意逻辑冲突!
  2. 触发条件(超级重要!) :
    • 仅用户双击触发;
    • 代码操作 / 单击均不触发;
  3. 参数有效性 :row/column 始终为有效范围,无需额外校验。
4.2.2 使用示例
复制代码
#include <QTableWidgetItem>
#include <QInputDialog>
#include <QLineEdit>

// 绑定信号(用 Lambda 表达式)
connect(ui->tableWidget, &QTableWidget::cellDoubleClicked,
        this, [=](int row, int col){
    // 获取该单元格
    QTableWidgetItem* item = ui->tableWidget->item(row, col);
    if (item == nullptr) {
        // 无单元格时创建新单元格
        item = new QTableWidgetItem();
        ui->tableWidget->setItem(row, col, item);
    }
    // 弹出输入框编辑文本
    QString newText = QInputDialog::getText(this, "编辑单元格",
                                             "修改内容:",
                                             QLineEdit::Normal,
                                             item->text());
    if (!newText.isEmpty()) {
        item->setText(newText);
    }
});

4.3 信号三:cellEntered (int row, int column)------ 鼠标光标进入单元格时触发

4.3.1 信号的核心定义

cellEntered 是 QTableWidget 用于鼠标悬浮交互 的信号 ------ 它在鼠标光标进入单元格区域时触发,需开启鼠标跟踪才会触发!

通俗理解:cellEntered 就像 "鼠标移到表格里的某个小格子上时通知你"------ 你可以用它做 "鼠标悬浮高亮单元格""显示 Tooltip 提示" 等效果;但注意,你必须先开启鼠标跟踪,否则它不会通知你!

这里有几个超级重要的规则,必须牢记,刻在脑子里:

  1. 前置条件!(超级重要!说三遍!) :
    • 必须调用 setMouseTracking(true)!
    • 否则永不触发此信号!
    • 这是新手最容易忽略的!
  2. 触发频率(超级重要!) :
    • 鼠标在单元格间移动时高频触发;
    • 避免在信号槽内执行耗时操作!
  3. 仅进不出(超级重要!) :
    • 此信号仅响应 "鼠标进入" 单元格;
    • 鼠标离开单元格需结合 QMouseEvent 手动处理(没有 cellLeft 信号);
  4. 参数有效性 :row/column 始终为有效范围,无需额外校验。
4.3.2 使用示例
复制代码
#include <QTableWidgetItem>
#include <QGuiApplication> // Qt::lightGray

// 【必须!】第一步:开启表格的鼠标跟踪!
ui->tableWidget->setMouseTracking(true);

// 第二步:绑定信号(用 Lambda 表达式)
connect(ui->tableWidget, &QTableWidget::cellEntered,
        this, [=](int row, int col){
    // 获取该单元格
    QTableWidgetItem* item = ui->tableWidget->item(row, col);
    if (item == nullptr) {
        item = new QTableWidgetItem();
        ui->tableWidget->setItem(row, col, item);
    }
    // 鼠标进入时设置浅灰背景
    item->setBackground(Qt::lightGray);
    // 注意:鼠标离开时恢复背景需结合鼠标事件手动处理
});

4.4 信号四:currentCellChanged (int row, int column, int previousRow, int previousColumn)------ 选中不同单元格时触发

4.4.1 信号的核心定义

currentCellChanged 是 QTableWidget 最核心、最常用 的选中变更信号 ------ 它在选中不同单元格时触发(选中同一条目不触发),同时返回 "当前选中单元格" 和 "上一个选中单元格" 的行 / 列号。

通俗理解:currentCellChanged 就像 "表格上标亮的格子变了时通知你"------ 它会告诉你 "之前标亮的是第几行第几列,现在标亮的是第几行第几列";如果你重复点击同一个格子,它不会通知你,因为标亮的格子没变。

这里有几个超级重要的规则,必须牢记:

  1. 判空处理(超级重要!) :
    • 当前 / 上一个选中项不存在时,对应行 / 列号为 -1;
    • 需先校验再操作!
  2. 触发规则(超级重要!) :
    • 仅选中不同单元格时触发;
    • 重复选中同一条目不触发;
  3. 代码触发(超级重要!) :
    • 调用 setCurrentCell() / setCurrentItem() 等代码选中单元格也会触发此信号;
  4. 取消选中 :删除选中单元格时,row/column 为 -1,previousRow/previousColumn 为原选中单元格位置。
4.4.2 信号参数详解

信号原型:

复制代码
void QTableWidget::currentCellChanged(int row, int column, int previousRow, int previousColumn);

参数说明:

  • row:int 类型,当前选中单元格的行号(无选中时为 -1);
  • column:int 类型,当前选中单元格的列号(无选中时为 -1);
  • previousRow:int 类型,上一个选中单元格的行号(无之前选中项时为 -1);
  • previousColumn:int 类型,上一个选中单元格的列号(无之前选中项时为 -1)。
4.4.3 使用示例
复制代码
#include <QDebug>

// 绑定信号(用 Lambda 表达式)
connect(ui->tableWidget, &QTableWidget::currentCellChanged,
        this, [=](int curRow, int curCol, int prevRow, int prevCol){
    // 处理上一个选中位置
    QString prevPos;
    if (prevRow == -1 || prevCol == -1) {
        prevPos = "无";
    } else {
        prevPos = QString("第%1行第%2列").arg(prevRow+1).arg(prevCol+1);
    }
    // 处理当前选中位置
    QString curPos;
    if (curRow == -1 || curCol == -1) {
        curPos = "无";
    } else {
        curPos = QString("第%1行第%2列").arg(curRow+1).arg(curCol+1);
    }
    // 打印变更记录
    qDebug() << "选中单元格变更:" << prevPos << " → " << curPos;
});

示例代码:

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //OK,本文件我们来学习QTableWidget的核心信号,其实这个就真的是很简单·~~·

    /**
     * @class QTableWidget
     * @brief Qt中表格控件的核心单元格交互信号(注:以下信号归属QTableWidget,非QTableWidgetItem)
     * @details 这些信号覆盖QTableWidget最核心的单元格交互场景(点击、双击、鼠标悬浮、选中变更),是表格与业务逻辑联动的核心接口;
     *          所有信号均返回单元格的行/列号(从0开始),可精准定位交互目标,适配各类表格操作场景。
     *
     * 【核心特征】
     * 1. 点击交互:支持单击/双击单元格触发信号,直接返回目标单元格的行/列号;
     * 2. 悬浮交互:支持鼠标进入单元格触发信号(需开启鼠标跟踪);
     * 3. 选中变更:支持选中单元格切换时触发信号,同时返回当前/之前选中单元格的位置。
     */

    // ============================== 核心信号详解 ==============================

    /**
     * @signal void QTableWidget::cellClicked(int row, int column)
     * @brief **用户鼠标单击**表格单元格时触发的信号
     * @details 纯交互触发信号,仅响应用户单击单元格操作,参数返回被点击单元格的行/列号;
     *          点击表格空白区域(无单元格处)不会触发此信号。
     *
     * @参数说明:
     * @param row - int类型,被点击单元格的行号(从0开始计数);
     * @param column - int类型,被点击单元格的列号(从0开始计数)。
     *
     * @使用示例:
     * // 绑定信号,单击单元格时打印位置并修改文本
     * connect(ui->tableWidget, &QTableWidget::cellClicked, this, [=](int row, int col){
     *     qDebug() << "单击单元格:第" << row+1 << "行,第" << col+1 << "列";
     *     QTableWidgetItem* item = ui->tableWidget->item(row, col);
     *     if (item) {
     *         item->setText("已单击");
     *     }
     * });
     *
     * 【关键注意事项】
     * 1. 触发条件:仅用户**单击**单元格触发,代码选中单元格(setCurrentCell)不触发;
     * 2. 参数有效性:row/column始终为有效范围(0 ≤ row < rowCount(),0 ≤ column < columnCount());
     * 3. 选中联动:单击单元格会自动将其设为当前选中单元格,因此会先触发cellClicked(),再触发currentCellChanged();
     * 4. 空白区:点击表格空白处(无单元格区域)不触发此信号。
     */

    /**
     * @signal void QTableWidget::cellDoubleClicked(int row, int column)
     * @brief **用户鼠标双击**表格单元格时触发的信号
     * @details 适配"双击单元格执行核心操作"的场景(如编辑单元格、打开详情),参数返回被双击单元格的行/列号。
     *
     * @参数说明:
     * @param row - int类型,被双击单元格的行号(从0开始计数);
     * @param column - int类型,被双击单元格的列号(从0开始计数)。
     *
     * @使用示例:
     * // 绑定信号,双击单元格时编辑文本
     * connect(ui->tableWidget, &QTableWidget::cellDoubleClicked, this, [=](int row, int col){
     *     QTableWidgetItem* item = ui->tableWidget->item(row, col);
     *     if (!item) {
     *         // 无单元格时创建新单元格
     *         item = new QTableWidgetItem();
     *         ui->tableWidget->setItem(row, col, item);
     *     }
     *     QString newText = QInputDialog::getText(this, "编辑单元格", "修改内容:",
     *                                             QLineEdit::Normal, item->text());
     *     if (!newText.isEmpty()) {
     *         item->setText(newText);
     *     }
     * });
     *
     * 【关键注意事项】
     * 1. 触发顺序:双击会先触发cellClicked()(第一次单击),再触发此信号;
     * 2. 触发条件:仅用户**双击**触发,代码操作/单击均不触发;
     * 3. 参数有效性:row/column始终为有效范围,无需额外校验;
     * 4. 交互场景:适合"编辑、查看详情、打开关联数据"等需要双击确认的操作。
     */

    /**
     * @signal void QTableWidget::cellEntered(int row, int column)
     * @brief **鼠标光标进入**表格单元格区域时触发的信号(需开启鼠标跟踪)
     * @details 悬浮交互信号,用于实现"鼠标悬浮高亮单元格、显示提示信息"等效果;
     *          默认关闭鼠标跟踪,需手动调用setMouseTracking(true)才会触发。
     *
     * @参数说明:
     * @param row - int类型,鼠标进入的单元格行号(从0开始计数);
     * @param column - int类型,鼠标进入的单元格列号(从0开始计数)。
     *
     * @使用示例:
     * // 第一步:开启表格的鼠标跟踪
     * ui->tableWidget->setMouseTracking(true);
     * // 第二步:绑定信号,悬浮时高亮单元格背景
     * connect(ui->tableWidget, &QTableWidget::cellEntered, this, [=](int row, int col){
     *     QTableWidgetItem* item = ui->tableWidget->item(row, col);
     *     if (!item) {
     *         item = new QTableWidgetItem();
     *         ui->tableWidget->setItem(row, col, item);
     *     }
     *     item->setBackground(Qt::lightGray); // 悬浮时设浅灰背景
     *     // 鼠标离开时恢复背景需结合鼠标事件实现
     * });
     *
     * 【关键注意事项】
     * 1. 前置条件:必须调用setMouseTracking(true),否则永不触发此信号;
     * 2. 触发频率:鼠标在单元格间移动时高频触发,避免在信号槽内执行耗时操作;
     * 3. 仅进不出:此信号仅响应"鼠标进入",鼠标离开单元格需结合QMouseEvent手动处理;
     * 4. 参数有效性:row/column始终为有效范围,无需额外校验。
     */

    /**
     * @signal void QTableWidget::currentCellChanged(int row, int column, int previousRow, int previousColumn)
     * @brief 选中**不同**单元格时触发的信号(选中同一条目不触发)
     * @details 核心选中变更信号,同时返回"当前选中单元格"和"上一个选中单元格"的行/列号;
     *          触发场景包括用户点击不同单元格、代码设置选中单元格、删除选中单元格等。
     *
     * @参数说明:
     * @param row - int类型,当前选中单元格的行号(无选中时为-1);
     * @param column - int类型,当前选中单元格的列号(无选中时为-1);
     * @param previousRow - int类型,上一个选中单元格的行号(无之前选中项时为-1);
     * @param previousColumn - int类型,上一个选中单元格的列号(无之前选中项时为-1)。
     *
     * @使用示例:
     * // 绑定信号,打印选中单元格的变更记录
     * connect(ui->tableWidget, &QTableWidget::currentCellChanged, this,
     *         [=](int curRow, int curCol, int prevRow, int prevCol){
     *     QString prevPos = (prevRow == -1) ? "无" : QString("第%1行第%2列").arg(prevRow+1).arg(prevCol+1);
     *     QString curPos = (curRow == -1) ? "无" : QString("第%1行第%2列").arg(curRow+1).arg(curCol+1);
     *     qDebug() << "选中单元格变更:" << prevPos << " → " << curPos;
     * });
     *
     * 【关键注意事项】
     * 1. 判空处理:当前/上一个选中项不存在时,对应行/列号为-1,需先校验再操作;
     * 2. 触发规则:仅选中**不同**单元格时触发(重复选中同一条目不触发);
     * 3. 代码触发:调用setCurrentCell()/setCurrentItem()等代码选中单元格也会触发此信号;
     * 4. 取消选中:删除选中单元格时,row/column为-1,prevRow/prevCol为原选中单元格位置。
     */

    //我们使用ui界面~

    // 【必须】设置表格的行列数量
    //要严格注意,在插入条目之前,必须先指明表格的行列数量才行哦~~~
    ui->tw->setRowCount(2);    // 2行
    ui->tw->setColumnCount(2); // 2列

    //然后还有就是,一般在我们设置完表格的行列数量之后
    //qt就会自动在表格的上方和左方加上表头,1、2什么的
    //要是我们想自定义,那么就得使用上面提到的
    //setHorizonalHeaderItem方法和setVerticalHeaderItem方法
    //指明是横还是竖的哪一行哪一列,然后进行设置
    //注意:从0开始计数

    // ================= 设置水平表头 (列标题) =================
    // 注意:第二个参数必须是 QTableWidgetItem* 对象

    // 第 0 列 表头
    QTableWidgetItem* headerItem0 = new QTableWidgetItem("姓名");
    // 可选:设置表头文字居中
    headerItem0->setTextAlignment(Qt::AlignCenter);
    ui->tw->setHorizontalHeaderItem(0, headerItem0);

    // 第 1 列 表头
    QTableWidgetItem* headerItem1 = new QTableWidgetItem("年龄");
    headerItem1->setTextAlignment(Qt::AlignCenter);
    ui->tw->setHorizontalHeaderItem(1, headerItem1);

    // ================= 设置垂直表头 (行标题) =================
    // 如果你想自定义左侧的行号 (默认是 1, 2, 3...)

    // 第 0 行 表头
    QTableWidgetItem* vHeaderItem0 = new QTableWidgetItem("第一行");
    ui->tw->setVerticalHeaderItem(0, vHeaderItem0);

    // 第 1 行 表头
    QTableWidgetItem* vHeaderItem1 = new QTableWidgetItem("第二行");
    ui->tw->setVerticalHeaderItem(1, vHeaderItem1);


    // ================= 填充表格内容 =================
    QTableWidgetItem* item1 = new QTableWidgetItem("张三");
    QTableWidgetItem* item2 = new QTableWidgetItem("18");
    QTableWidgetItem* item3 = new QTableWidgetItem("李四");
    QTableWidgetItem* item4 = new QTableWidgetItem("20");

    // 放入表格,要指定行和列哦~~~
    ui->tw->setItem(0, 0, item1);
    ui->tw->setItem(0, 1, item2);
    ui->tw->setItem(1, 0, item3);
    ui->tw->setItem(1, 1, item4);

    ui->tw->setMouseTracking(true);//开启鼠标追踪
}

Widget::~Widget()
{
    delete ui;
}


// 1. 单元格被单击
void Widget::on_tw_itemClicked(QTableWidgetItem *item)
{
    // 触发时机:鼠标左键单击某个单元格时触发。
    // 注意:如果点击的是已经选中的单元格,currentItemChanged 不会触发,但这个信号会触发。

    if (!item) return; // 安全判断

    int row = item->row();
    int col = item->column();
    QString text = item->text();

    qDebug() << "[Table Clicked] 点击了单元格 -> 行:" << row << ", 列:" << col << ", 内容:" << text;

    // 典型用法:
    // 1. 记录当前点击位置,用于后续操作(如右键菜单)。
    // 2. 在状态栏显示当前单元格的详细信息。
    // ui->statusBar->showMessage(QString("当前位置: %1 行, %2 列").arg(row).arg(col));
}

// 2. 单元格被双击
void Widget::on_tw_itemDoubleClicked(QTableWidgetItem *item)
{
    // 触发时机:快速双击某个单元格时触发。

    if (!item) return;

    int row = item->row();
    int col = item->column();

    qDebug() << "[Table Double Clicked] 双击了单元格 -> 行:" << row << ", 列:" << col;

    // 典型用法:
    // 1. 进入"编辑模式"(如果默认不可编辑)。
    // 2. 打开详情对话框,加载该行数据。
    // 3. 如果该单元格是文件路径,直接打开文件。

    // 示例:强制开启编辑
    // ui->tw->editItem(item);
}

// 3. 鼠标移入单元格
void Widget::on_tw_itemEntered(QTableWidgetItem *item)
{
    // 触发时机:鼠标光标移入某个单元格区域时触发。
    // 前提:确保 tableWidget 的 viewport 开启了鼠标追踪 (通常默认开启,若无效可手动设置)。
    // ui->tw->viewport()->setMouseTracking(true);

    if (!item) return;

    QString tipContent = QString("第 %1 行,第 %2 列\n内容:%3")
                             .arg(item->row())
                             .arg(item->column())
                             .arg(item->text());

    // 典型用法:
    // 1. 显示 Tooltip,特别是当文字被截断时显示完整内容。
    // 2. 动态高亮当前行或当前列(通过 QSS 或背景色)。

    item->setToolTip(tipContent);

    // 示例:高亮当前行背景 (临时效果)
    // QColor oldColor = item->background().color();
    // item->setBackground(QColor("#E0F7FA"));
    // (注意:需要在离开时恢复颜色,通常配合 item 的其他逻辑或使用 StyleSheet)
}

// 4. 当前选中单元格改变
void Widget::on_tw_currentItemChanged(QTableWidgetItem *current, QTableWidgetItem *previous)
{
    // 触发时机:当"当前活动单元格"(有焦点框的那个)发生变化时触发。
    // 参数说明:
    //   current: 新选中的单元格指针 (若取消选中则为 nullptr)
    //   previous: 原来选中的单元格指针

    qDebug() << "[Current Item Changed]";

    if (current) {
        int r = current->row();
        int c = current->column();
        qDebug() << "新选中 -> 行:" << r << ", 列:" << c << ", 文本:" << current->text();

        // 典型用法:
        // 1. 联动更新其他控件(例如:选中表格某行,右侧表单显示该行详情)。
        // 2. 根据列的不同执行不同逻辑(例如:只有点击"价格"列才显示货币转换器)。

        // 示例:根据列号判断逻辑
        /*
        if (c == 2) { // 假设第3列是操作列
            ui->btnEdit->setEnabled(true);
        } else {
            ui->btnEdit->setEnabled(false);
        }
        */
    } else {
        qDebug() << "已取消所有选中";
        // 清空关联的详情显示
        // ui->lineEditDetail->clear();
    }
}

第五章 综合示例:学生信息管理表格

讲完了所有内容,我们最后来做一个综合示例,结合你提供的资料,实现一个完整的 "学生信息管理表格"------ 这是 QTableWidget 最经典的应用场景之一。

5.1 场景描述

界面上有:

  1. 一个 QTableWidget(objectName 为 tableWidget);
  2. 四个 QPushButton:
    • pushButton_addRow:添加新行;
    • pushButton_delRow:删除选中行;
    • pushButton_addCol:添加新列(需配合 QLineEdit 输入列名);
    • pushButton_delCol:删除选中列;
  3. 一个 QLineEdit(objectName 为 lineEdit_colName):用于输入新列的列名。

功能:

  • 初始化表格:3 行 3 列,列标题为 "学号""姓名""年龄",填充初始数据;
  • 点击 "添加新行":在表格末尾插入一行空行;
  • 点击 "删除选中行":删除当前选中的行;
  • 点击 "添加新列":在表格末尾插入一列,列标题为 LineEdit 中的内容;
  • 点击 "删除选中列":删除当前选中的列;
  • 绑定交互信号:点击、双击、悬浮、选中变更时打印日志。

5.2 代码实现

复制代码
#include "widget.h"
#include "ui_widget.h"
#include <QTableWidgetItem>
#include <QFont>
#include <QDebug>
#include <QInputDialog>
#include <QLineEdit>
#include <QGuiApplication>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    // ================= 1. 初始化表格结构 =================
    // 【必须!】设置行列数
    ui->tableWidget->setRowCount(3);    // 3 行
    ui->tableWidget->setColumnCount(3); // 3 列

    // ================= 2. 设置水平表头(列标题) =================
    QStringList headers = {"学号", "姓名", "年龄"};
    for (int c = 0; c < headers.size(); ++c) {
        QTableWidgetItem* headerItem = new QTableWidgetItem(headers[c]);
        headerItem->setFont(QFont("微软雅黑", 12, QFont::Bold)); // 表头加粗
        headerItem->setTextAlignment(Qt::AlignCenter); // 表头居中
        ui->tableWidget->setHorizontalHeaderItem(c, headerItem);
    }

    // ================= 3. 填充初始数据 =================
    // 第 1 行(索引 0)
    ui->tableWidget->setItem(0, 0, new QTableWidgetItem("1001"));
    ui->tableWidget->setItem(0, 1, new QTableWidgetItem("张三"));
    ui->tableWidget->setItem(0, 2, new QTableWidgetItem("20"));
    // 第 2 行(索引 1)
    ui->tableWidget->setItem(1, 0, new QTableWidgetItem("1002"));
    ui->tableWidget->setItem(1, 1, new QTableWidgetItem("李四"));
    ui->tableWidget->setItem(1, 2, new QTableWidgetItem("21"));
    // 第 3 行(索引 2)
    ui->tableWidget->setItem(2, 0, new QTableWidgetItem("1003"));
    ui->tableWidget->setItem(2, 1, new QTableWidgetItem("王五"));
    ui->tableWidget->setItem(2, 2, new QTableWidgetItem("19"));

    // ================= 4. 开启鼠标跟踪(用于 cellEntered 信号) =================
    ui->tableWidget->setMouseTracking(true);

    // ================= 5. 绑定交互信号 =================
    // 信号 1:cellClicked(单击单元格)
    connect(ui->tableWidget, &QTableWidget::cellClicked,
            this, [=](int row, int col){
        qDebug() << "[单击] 第" << row+1 << "行,第" << col+1 << "列";
    });

    // 信号 2:cellDoubleClicked(双击单元格)
    connect(ui->tableWidget, &QTableWidget::cellDoubleClicked,
            this, [=](int row, int col){
        qDebug() << "[双击] 第" << row+1 << "行,第" << col+1 << "列";
        // 双击编辑
        QTableWidgetItem* item = ui->tableWidget->item(row, col);
        if (item == nullptr) {
            item = new QTableWidgetItem();
            ui->tableWidget->setItem(row, col, item);
        }
        QString newText = QInputDialog::getText(this, "编辑", "修改内容:",
                                                 QLineEdit::Normal, item->text());
        if (!newText.isEmpty()) {
            item->setText(newText);
        }
    });

    // 信号 3:cellEntered(鼠标进入单元格)
    connect(ui->tableWidget, &QTableWidget::cellEntered,
            this, [=](int row, int col){
        Q_UNUSED(row);
        Q_UNUSED(col);
        // 这里可以做悬浮高亮,为了简单我们就不实现恢复背景了
        // qDebug() << "[悬浮] 第" << row+1 << "行,第" << col+1 << "列";
    });

    // 信号 4:currentCellChanged(选中变更)
    connect(ui->tableWidget, &QTableWidget::currentCellChanged,
            this, [=](int curRow, int curCol, int prevRow, int prevCol){
        Q_UNUSED(prevRow);
        Q_UNUSED(prevCol);
        if (curRow != -1 && curCol != -1) {
            qDebug() << "[选中变更] 当前:第" << curRow+1 << "行,第" << curCol+1 << "列";
        } else {
            qDebug() << "[选中变更] 无选中";
        }
    });
}

Widget::~Widget()
{
    delete ui;
}

// ================= 按钮槽函数 =================

// 1. 添加新行
void Widget::on_pushButton_addRow_clicked()
{
    int rowCount = ui->tableWidget->rowCount();
    ui->tableWidget->insertRow(rowCount); // 在末尾插入
    qDebug() << "[操作] 添加新行,当前总行数:" << ui->tableWidget->rowCount();
}

// 2. 删除选中行
void Widget::on_pushButton_delRow_clicked()
{
    int curRow = ui->tableWidget->currentRow();
    if (curRow != -1) {
        ui->tableWidget->removeRow(curRow);
        qDebug() << "[操作] 删除第" << curRow+1 << "行,当前总行数:" << ui->tableWidget->rowCount();
    } else {
        qDebug() << "[操作] 未选中行,无法删除";
    }
}

// 3. 添加新列
void Widget::on_pushButton_addCol_clicked()
{
    const QString& colName = ui->lineEdit_colName->text();
    if (colName.isEmpty()) {
        qDebug() << "[操作] 列名为空,无法添加";
        return;
    }
    int colCount = ui->tableWidget->columnCount();
    ui->tableWidget->insertColumn(colCount); // 在末尾插入
    // 设置新列的表头
    QTableWidgetItem* headerItem = new QTableWidgetItem(colName);
    headerItem->setFont(QFont("微软雅黑", 12, QFont::Bold));
    headerItem->setTextAlignment(Qt::AlignCenter);
    ui->tableWidget->setHorizontalHeaderItem(colCount, headerItem);
    // 清空 LineEdit
    ui->lineEdit_colName->clear();
    qDebug() << "[操作] 添加新列:" << colName << ",当前总列数:" << ui->tableWidget->columnCount();
}

// 4. 删除选中列
void Widget::on_pushButton_delCol_clicked()
{
    int curCol = ui->tableWidget->currentColumn();
    if (curCol != -1) {
        ui->tableWidget->removeColumn(curCol);
        qDebug() << "[操作] 删除第" << curCol+1 << "列,当前总列数:" << ui->tableWidget->columnCount();
    } else {
        qDebug() << "[操作] 未选中列,无法删除";
    }
}

第六章 全文总结与学习建议

恭喜你!终于看完了这篇 QTableWidget 与 QTableWidgetItem 详细解析!

如果你跟着文章一步步敲了代码,做了练习,那么现在你已经完全掌握了它们的核心内容:

  • 你知道了 QTableWidget 是二维表格控件,QTableWidgetItem 是表格中的单个单元格;
  • 你会用 QTableWidgetItem 的 row、column、setText、setTextAlignment、setIcon、setSelected、setSizeHint、setFont 定制单元格;
  • 你会用 QTableWidget 的 item、setItem、currentItem、currentRow、currentColumn、rowCount、columnCount、insertRow、insertColumn、removeRow、removeColumn、setHorizontalHeaderItem、setVerticalHeaderItem 操作表格;
  • 你会绑定 cellClicked、cellDoubleClicked、cellEntered、currentCellChanged 等信号实现交互;
  • 你知道了在插入条目之前必须先设置行列数! 行列从 0 开始! removeRow/removeColumn 会自动释放单元格! cellEntered 必须先开启鼠标跟踪! 这些超级重要的注意事项。

毫不夸张地说,掌握了这些内容,你就掌握了 QTableWidget 开发的 95% 以上的需求!

6.1 核心要点回顾(最后再记一遍!)

在结束之前,我们最后再回顾一下这篇文章的核心要点,特别是那些最容易踩坑的地方:

  1. 在插入条目之前必须先设置行列数!(超级重要!开篇就讲!);
  2. 行列从 0 开始!(超级重要!说三遍!):用户视角需 +1;
  3. item ()、currentItem () 必须先判空!(超级重要!):否则程序崩溃!
  4. removeRow/removeColumn 会自动释放单元格!(超级重要!):无需手动 delete!
  5. setItem () 设置新单元格前,原单元格需手动 delete!(超级重要!);
  6. cellEntered 必须先调用 setMouseTracking (true)!(超级重要!);
  7. 图标显示尺寸由 QTableWidget::setIconSize () 全局控制!(超级重要!);
  8. QFont 不包含颜色,文本颜色需通过 setForeground () 设置!(超级重要!);
  9. cellClicked 仅用户单击触发,代码选中不触发!(超级重要!);
  10. 重复点击同一单元格,cellClicked 触发,currentCellChanged 不触发!(超级重要!)。

6.2 最后的话

编程学习没有捷径,唯手熟尔。QTableWidget 和 QTableWidgetItem 的内容虽然不少,但只要你多敲代码、多做练习、多踩坑、多排查,很快就能熟练掌握。

这篇文章虽然很长,但我相信,如果你认真看完了,跟着敲了代码,你一定会对它们有一个极其深刻的理解,再也不会为表格开发发愁。

感谢你阅读这篇文章,希望它能帮到你。我们下一篇 Qt 教程再见

相关推荐
ShineWinsu1 小时前
对于Qt:QListWidget常见属性以及QListWidgetItem类的解析
开发语言·c++·qt·客户端·列表·qlistwidget·qlistwidgetitem
坤坤子吖2 小时前
Linux网络编程:自定义应用层协议与 JSON 序列化
linux·服务器·网络·c++·笔记·json
吴名氏.2 小时前
Java转AI Agent教程(第十二周)检索与切分
java·开发语言·人工智能·ai·ai agent
瑞雪兆丰年兮2 小时前
JavaWeb-day10-SpringBootWeb案例
java·开发语言·javaweb·web
Elastic 中国社区官方博客2 小时前
更少的位数,相同的召回率:DiskBBQ 更保守的自动校准扫描
大数据·运维·开发语言·人工智能·elasticsearch·搜索引擎
三雷科技3 小时前
第6章第4节:自定义分词器
开发语言·c#
沫璃染墨3 小时前
从零入门计算机网络系列(十八):TCP连接管理详解——从三次握手与四次挥手到TIME_WAIT机制
运维·服务器·网络·c++·网络协议·tcp/ip·tcp
Adellle4 小时前
设计模式指南 (Java 版) ㊁
java·开发语言·设计模式
Delightrs4 小时前
Rust LeetCode238 算法题解
开发语言·算法·rust