QT基础十、表格组件:QTableWidget
目录
一、简介
二、主要特性
三、项目演练
1、新建一个项目,导入自己喜欢的图片
2、添加工具栏与action
3、初始化数据
函数 initTableData
函数 createRowData
4、生成action与tabelWidget槽函数
函数 on_actionInsert_triggered()
函数 on_actionDel_triggered()
函数 on_actionEdit_triggered(bool checked)
函数 on_tableWidget_itemSelectionChanged()
5、增加搜索功能
在头文件mainwindow.h添加
函数 initLineEditSearch()
函数 on_searchBtn_clicked()
在tableWidget生成一个 on_tableWidget_cellClicked(int, int)
6、运行结果
四、项目代码
1、mainwindow.h
2、mainwindow.cpp
一、简介
QTableWidget
是 Qt 框架中的一个控件,用于显示和编辑表格数据。它是基于 QTableView
的高级实现,提供了一个更简单、更直接的方式来操作表格数据,而无需深入理解底层的模型-视图架构(Model-View Architecture)。QTableWidget
内部使用了默认的 QTableWidgetItem
来存储和管理表格中的单元格数据。
二、主要特性
-
表格结构 :
- 表格由行和列组成,每个单元格可以包含文本、图标或其他内容。
- 支持动态调整行数和列数。
-
单元格操作 :
- 每个单元格的内容可以通过
QTableWidgetItem
进行设置和读取。 - 支持单元格的编辑、选择、排序等操作。
- 每个单元格的内容可以通过
-
交互功能 :
- 用户可以直接在单元格中输入或修改数据。
- 支持多选模式(如单选、多选、扩展选择等)。
-
自定义外观 :
- 可以通过样式表(QSS)或自定义委托(Delegate)来改变表格的外观。
- 支持设置表头(水平表头和垂直表头)的文本、图标等。
-
信号与槽 :
- 提供丰富的信号(如单元格点击、双击、选择变化等),方便开发者响应用户操作。
三、项目演练
1、新建一个项目,导入自己喜欢的图片
导入图片的步骤,我上一期已经演示过,这一期就不演示了,图片需要能代表头像、插入、编辑、删除。
2、添加工具栏与action
具体步骤我在上一期也演示了,文档实在是不好演示,若看上一期看不懂,建议看视频
插入与输出不用勾选Checkable,编辑因为有编辑模式和非编辑模式,所以需要勾选Checkable
最终界面样式
3、初始化数据
可以用数据库,不过我这一期不演示,以后会专门出一期数据库相关的知识
这里我们需要用到两个函数,initTableData() 是初始化整个表格数据,再将初始化一整行数据的功能封装成一个函数,可以减少代码的冗余度,因为你插入数据时也需要初始化一整行数据,到时候直接调用 createRowData() 函数就行。
函数 initTableData
void MainWindow::initTableData()
{
// 定义表头内容:包括姓名、性别、出生日期、专业、是否毕业
QStringList headList = {"姓名", "性别", "出生日期", "专业", "是否毕业"};
// 设置表格的列数为表头的数量
ui->tableWidget->setColumnCount(headList.count());
// 遍历表头列表,设置每一列的表头项
for (int i = 0; i < headList.size(); i++) {
// 创建一个新的 QTableWidgetItem 对象,用于存储表头文本
auto* item = new QTableWidgetItem(headList[i]);
// 设置表头字体样式
QFont font = item->font();
font.setBold(true); // 字体加粗
font.setFamily("微软雅黑"); // 设置字体为微软雅黑
font.setPointSize(14); // 设置字体大小为 14
item->setFont(font);
// 设置表头文字颜色为红色
item->setForeground(Qt::red);
// 将表头项设置到表格的水平表头中
ui->tableWidget->setHorizontalHeaderItem(i, item);
}
// 获取表格的水平表头对象,并设置列宽自动伸展模式
auto* headerView = ui->tableWidget->horizontalHeader();
headerView->setSectionResizeMode(QHeaderView::Stretch);
// 设置第二列(性别列)为固定宽度,不随窗口调整而变化
headerView->setSectionResizeMode(1, QHeaderView::Fixed);
// 设置表格的行数为 100 行
int row = 100;
ui->tableWidget->setRowCount(row);
// 循环生成 100 行数据
for (int i = 0; i < row; i++) {
maxNum++; // 员工编号递增
// 随机生成员工信息
QString name = QString::asprintf("员工%d", i + 1); // 姓名
QString sex = (rand() % 2) ? "男" : "女"; // 性别
QDate date(rand() % 10 + 2000, rand() % 12 + 1, rand() % 28 + 1); // 出生日期
QStringList subjects = {"软件工程", "计算机科学与技术", "通信工程", "网络工程"}; // 专业列表
bool graduate = (rand() % 2) ? true : false; // 是否毕业
// 调用 createRowData 函数,将生成的数据填充到表格中
createRowData(i, name, maxNum, sex, date,
subjects[rand() % subjects.size()], graduate);
}
}
函数 createRowData
void MainWindow::createRowData(int index, QString name, int number, QString sex, QDate birthday, QString subject, bool graduate)
{
// 创建一个 QList,用于存储每一行的 QTableWidgetItem 对象
QList<QTableWidgetItem*> items;
// 姓名列
items.append(new QTableWidgetItem(name));
items[0]->setData(Qt::UserRole, QVariant(number)); // 使用 UserRole 存储员工编号
// 性别列
items.append(new QTableWidgetItem(sex));
QIcon icon((sex == "男") ? ":/image/boy.png" : ":/image/girl.png"); // 根据性别设置图标
items[1]->setIcon(icon);
// 出生日期列
items.append(new QTableWidgetItem(birthday.toString("yyyy-MM-dd"))); // 格式化日期为字符串
// 专业列
items.append(new QTableWidgetItem(subject));
// 是否毕业列
items.append(new QTableWidgetItem(graduate ? "已毕业" : "未毕业"));
// 循环遍历所有列,设置单元格内容居中对齐,并将其添加到表格中
for (int i = 0; i < items.size(); i++) {
items[i]->setTextAlignment(Qt::AlignCenter); // 设置单元格内容居中对齐
ui->tableWidget->setItem(index, i, items[i]); // 将单元格内容设置到表格中
}
}
4、生成action与tabelWidget槽函数
注:插入与删除,选择 triggered();编辑,选择triggered(bool)
函数 on_actionInsert_triggered()
void MainWindow::on_actionInsert_triggered()
{
//取出当前选中的行号,并记录插入的行号
int row = insertRow = ui->tableWidget->currentRow();
ui->tableWidget->insertRow(row);
maxNum++; // 员工编号递增
// 随机生成员工信息
QString name = "未知";
QString sex = "男";
QDate date(2000, 1, 1);
QString subject = "未知";
bool graduate = false;
// 调用 createRowData 函数,将生成的数据填充到表格中
createRowData(row, name, maxNum, sex, date,
subject, graduate);
//插入后,自动选择新行
ui->tableWidget->selectRow(row);
on_actionEdit_triggered(true);
}
函数 on_actionDel_triggered()
void MainWindow::on_actionDel_triggered()
{
// 获取当前选中的单元格项
auto* item = ui->tableWidget->currentItem();
// 检查该项是否被选中
if (item && item->isSelected()) {
// 删除该项所在的整行
ui->tableWidget->removeRow(item->row());
}
}
函数 on_actionEdit_triggered(bool checked)
void MainWindow::on_actionEdit_triggered(bool checked)
{
if (checked) {
// 如果编辑模式被启用,则设置编辑触发器为双击或单击选中项
ui->tableWidget->setEditTriggers(
QAbstractItemView::DoubleClicked |
QAbstractItemView::SelectedClicked);
} else {
// 如果编辑模式被禁用,则禁止所有编辑触发器
ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
}
}
函数 on_tableWidget_itemSelectionChanged()
//当用户选择不同的行时,系统会自动检查是否需要禁用编辑模式。
//只有在特定行(如插入行)中才允许编辑,其他行不允许编辑。
void MainWindow::on_tableWidget_itemSelectionChanged()
{
// 如果编辑模式已启用,则直接返回,不做任何处理
if (ui->actionEdit->isChecked()) return;
// 如果当前选中的行不是插入行(insertRow),则禁用编辑模式
if (ui->tableWidget->currentRow() != insertRow) {
on_actionEdit_triggered(false);
}
}
5、增加搜索功能
注:状态栏不好进行图形化拖拽,所以这里用代码实现
在头文件mainwindow.h添加
//私有槽函数
private slots:
void on_searchBtn_clicked();
//私有函数
private:
void initLineEditSearch();
//私有变量
private:
QLabel* label; //搜索
QLabel* info; //提示
QLineEdit* lineEditSearch; //搜索内容
QPushButton* searchBtn; //搜索按钮
函数 initLineEditSearch()
void MainWindow::initLineEditSearch()
{
// 创建一个 QLabel 对象,并设置其文本为“搜索”
label = new QLabel(this);
label->setText("搜索");
// 设置标签的字体大小为 14
auto font = label->font();
font.setPointSize(14);
label->setFont(font);
// 将标签添加到状态栏中
ui->statusbar->addWidget(label);
// 创建一个 QLineEdit 对象,用于输入搜索内容
lineEditSearch = new QLineEdit(this);
// 设置 QLineEdit 的最大宽度为 400 像素,避免占用过多空间
lineEditSearch->setMaximumWidth(400);
// 将 QLineEdit 添加到状态栏中
ui->statusbar->addWidget(lineEditSearch);
// 创建一个 QPushButton 对象,并设置其文本为“查找”
searchBtn = new QPushButton(this);
searchBtn->setText("查找");
// 设置按钮的字体大小为 14
font = searchBtn->font();
font.setPointSize(14);
searchBtn->setFont(font);
// 将按钮添加到状态栏中
ui->statusbar->addWidget(searchBtn);
// 连接按钮的 clicked() 信号到槽函数 on_searchBtn_clicked()
connect(searchBtn, SIGNAL(clicked()),
this, SLOT(on_searchBtn_clicked()));
// 创建一个 QLabel 对象,用于显示搜索结果或提示信息
info = new QLabel(this);
// 将信息标签添加到状态栏中
ui->statusbar->addWidget(info);
}
函数 on_searchBtn_clicked()
void MainWindow::on_searchBtn_clicked()
{
// 清除表格中之前的所有高亮选择
ui->tableWidget->clearSelection();
// 获取用户在搜索框中输入的关键字,并去除首尾空格
QString key = lineEditSearch->text().trimmed();
// 检查关键字是否非空
if (key.length() > 0) {
// 使用 findItems 方法查找包含关键字的所有项
auto items = ui->tableWidget->findItems(key, Qt::MatchContains);
// 遍历查找到的所有项,并将其设置为选中状态(高亮显示)
for (auto it = items.constBegin(); it != items.constEnd(); it++) {
(*it)->setSelected(true);
}
}
}
在tableWidget生成一个 on_tableWidget_cellClicked(int, int)
void MainWindow::on_tableWidget_cellClicked(int row, int column)
{
// 定义一个字符串变量,用于存储当前行的所有单元格内容
QString infoStr;
// 遍历表格的每一列,获取当前行的所有单元格内容
for (int i = 0; i < ui->tableWidget->columnCount(); i++) {
// 如果不是第一列,在内容前添加分隔符 "/"
if (i) infoStr += "/";
// 获取当前行第 i 列的单元格内容,并追加到 infoStr 中
infoStr += ui->tableWidget->item(row, i)->text();
}
// 将拼接好的字符串设置到信息标签中,显示在状态栏上
info->setText(infoStr);
}
6、运行结果
四、项目代码
1、mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QDate>
#include <QLineEdit>
#include <QLabel>
#include <QPushButton>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_actionInsert_triggered();
void on_actionDel_triggered();
void on_actionEdit_triggered(bool checked);
void on_tableWidget_itemSelectionChanged();
void on_searchBtn_clicked();
void on_tableWidget_cellClicked(int row, int column);
private:
void initTableData();
//姓名、性别、出生日期、专业、是否毕业
void createRowData(int index, QString name, int number, QString sex, QDate birthday,
QString subject, bool graduate);
void initLineEditSearch();
private:
Ui::MainWindow *ui;
QLabel* label;
QLabel* info;
QLineEdit* lineEditSearch;
QPushButton* searchBtn;
int maxNum;
int insertRow;
};
#endif // MAINWINDOW_H
2、mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
, maxNum(0)
{
ui->setupUi(this);
initTableData();
//禁止编辑
ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
initLineEditSearch();
ui->tableWidget->setStyleSheet(
"selection-background-color:rgb(255, 128, 0)");
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::initTableData()
{
// 定义表头内容:包括姓名、性别、出生日期、专业、是否毕业
QStringList headList = {"姓名", "性别", "出生日期", "专业", "是否毕业"};
// 设置表格的列数为表头的数量
ui->tableWidget->setColumnCount(headList.count());
// 遍历表头列表,设置每一列的表头项
for (int i = 0; i < headList.size(); i++) {
// 创建一个新的 QTableWidgetItem 对象,用于存储表头文本
auto* item = new QTableWidgetItem(headList[i]);
// 设置表头字体样式
QFont font = item->font();
font.setBold(true); // 字体加粗
font.setFamily("微软雅黑"); // 设置字体为微软雅黑
font.setPointSize(14); // 设置字体大小为 14
item->setFont(font);
// 设置表头文字颜色为红色
item->setForeground(Qt::red);
// 将表头项设置到表格的水平表头中
ui->tableWidget->setHorizontalHeaderItem(i, item);
}
// 获取表格的水平表头对象,并设置列宽自动伸展模式
auto* headerView = ui->tableWidget->horizontalHeader();
headerView->setSectionResizeMode(QHeaderView::Stretch);
// 设置第二列(性别列)为固定宽度,不随窗口调整而变化
headerView->setSectionResizeMode(1, QHeaderView::Fixed);
// 设置表格的行数为 100 行
int row = 100;
ui->tableWidget->setRowCount(row);
// 循环生成 100 行数据
for (int i = 0; i < row; i++) {
maxNum++; // 员工编号递增
// 随机生成员工信息
QString name = QString::asprintf("员工%d", i + 1); // 姓名
QString sex = (rand() % 2) ? "男" : "女"; // 性别
QDate date(rand() % 10 + 2000, rand() % 12 + 1, rand() % 28 + 1); // 出生日期
QStringList subjects = {"软件工程", "计算机科学与技术", "通信工程", "网络工程"}; // 专业列表
bool graduate = (rand() % 2) ? true : false; // 是否毕业
// 调用 createRowData 函数,将生成的数据填充到表格中
createRowData(i, name, maxNum, sex, date,
subjects[rand() % subjects.size()], graduate);
}
}
void MainWindow::createRowData(int index, QString name, int number, QString sex, QDate birthday,
QString subject, bool graduate)
{
// 创建一个 QList,用于存储每一行的 QTableWidgetItem 对象
QList<QTableWidgetItem*> items;
// 姓名列
items.append(new QTableWidgetItem(name));
items[0]->setData(Qt::UserRole, QVariant(number)); // 使用 UserRole 存储员工编号
// 性别列
items.append(new QTableWidgetItem(sex));
QIcon icon((sex == "男") ? ":/image/boy.png" : ":/image/girl.png"); // 根据性别设置图标
items[1]->setIcon(icon);
// 出生日期列
items.append(new QTableWidgetItem(birthday.toString("yyyy-MM-dd"))); // 格式化日期为字符串
// 专业列
items.append(new QTableWidgetItem(subject));
// 是否毕业列
items.append(new QTableWidgetItem(graduate ? "已毕业" : "未毕业"));
// 循环遍历所有列,设置单元格内容居中对齐,并将其添加到表格中
for (int i = 0; i < items.size(); i++) {
items[i]->setTextAlignment(Qt::AlignCenter); // 设置单元格内容居中对齐
ui->tableWidget->setItem(index, i, items[i]); // 将单元格内容设置到表格中
}
}
void MainWindow::initLineEditSearch()
{
// 创建一个 QLabel 对象,并设置其文本为“搜索”
label = new QLabel(this);
label->setText("搜索");
// 设置标签的字体大小为 14
auto font = label->font();
font.setPointSize(14);
label->setFont(font);
// 将标签添加到状态栏中
ui->statusbar->addWidget(label);
// 创建一个 QLineEdit 对象,用于输入搜索内容
lineEditSearch = new QLineEdit(this);
// 设置 QLineEdit 的最大宽度为 400 像素,避免占用过多空间
lineEditSearch->setMaximumWidth(400);
// 将 QLineEdit 添加到状态栏中
ui->statusbar->addWidget(lineEditSearch);
// 创建一个 QPushButton 对象,并设置其文本为“查找”
searchBtn = new QPushButton(this);
searchBtn->setText("查找");
// 设置按钮的字体大小为 14
font = searchBtn->font();
font.setPointSize(14);
searchBtn->setFont(font);
// 将按钮添加到状态栏中
ui->statusbar->addWidget(searchBtn);
// 连接按钮的 clicked() 信号到槽函数 on_searchBtn_clicked()
connect(searchBtn, SIGNAL(clicked()),
this, SLOT(on_searchBtn_clicked()));
// 创建一个 QLabel 对象,用于显示搜索结果或提示信息
info = new QLabel(this);
// 将信息标签添加到状态栏中
ui->statusbar->addWidget(info);
}
void MainWindow::on_actionInsert_triggered()
{
//取出当前选中的行号,并记录插入的行号
int row = insertRow = ui->tableWidget->currentRow();
ui->tableWidget->insertRow(row);
maxNum++; // 员工编号递增
// 随机生成员工信息
QString name = "未知";
QString sex = "男";
QDate date(2000, 1, 1);
QString subject = "未知";
bool graduate = false;
// 调用 createRowData 函数,将生成的数据填充到表格中
createRowData(row, name, maxNum, sex, date,
subject, graduate);
//插入后,自动选择新行
ui->tableWidget->selectRow(row);
on_actionEdit_triggered(true);
}
void MainWindow::on_actionDel_triggered()
{
// 获取当前选中的单元格项
auto* item = ui->tableWidget->currentItem();
// 检查该项是否被选中
if (item && item->isSelected()) {
// 删除该项所在的整行
ui->tableWidget->removeRow(item->row());
}
}
void MainWindow::on_actionEdit_triggered(bool checked)
{
if (checked) {
// 如果编辑模式被启用,则设置编辑触发器为双击或单击选中项
ui->tableWidget->setEditTriggers(
QAbstractItemView::DoubleClicked |
QAbstractItemView::SelectedClicked);
} else {
// 如果编辑模式被禁用,则禁止所有编辑触发器
ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
}
}
void MainWindow::on_tableWidget_itemSelectionChanged()
{
// 如果编辑模式已启用,则直接返回,不做任何处理
if (ui->actionEdit->isChecked()) return;
// 如果当前选中的行不是插入行(insertRow),则禁用编辑模式
if (ui->tableWidget->currentRow() != insertRow) {
on_actionEdit_triggered(false);
}
}
void MainWindow::on_searchBtn_clicked()
{
// 清除表格中之前的所有高亮选择
ui->tableWidget->clearSelection();
// 获取用户在搜索框中输入的关键字,并去除首尾空格
QString key = lineEditSearch->text().trimmed();
// 检查关键字是否非空
if (key.length() > 0) {
// 使用 findItems 方法查找包含关键字的所有项
auto items = ui->tableWidget->findItems(key, Qt::MatchContains);
// 遍历查找到的所有项,并将其设置为选中状态(高亮显示)
for (auto it = items.constBegin(); it != items.constEnd(); it++) {
(*it)->setSelected(true);
}
}
}
void MainWindow::on_tableWidget_cellClicked(int row, int column)
{
// 定义一个字符串变量,用于存储当前行的所有单元格内容
QString infoStr;
// 遍历表格的每一列,获取当前行的所有单元格内容
for (int i = 0; i < ui->tableWidget->columnCount(); i++) {
// 如果不是第一列,在内容前添加分隔符 "/"
if (i) infoStr += "/";
// 获取当前行第 i 列的单元格内容,并追加到 infoStr 中
infoStr += ui->tableWidget->item(row, i)->text();
}
// 将拼接好的字符串设置到信息标签中,显示在状态栏上
info->setText(infoStr);
}