当前位置: 首页 > article >正文

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 来存储和管理表格中的单元格数据。


二、主要特性

  1. 表格结构

    • 表格由行和列组成,每个单元格可以包含文本、图标或其他内容。
    • 支持动态调整行数和列数。
  2. 单元格操作

    • 每个单元格的内容可以通过 QTableWidgetItem 进行设置和读取。
    • 支持单元格的编辑、选择、排序等操作。
  3. 交互功能

    • 用户可以直接在单元格中输入或修改数据。
    • 支持多选模式(如单选、多选、扩展选择等)。
  4. 自定义外观

    • 可以通过样式表(QSS)或自定义委托(Delegate)来改变表格的外观。
    • 支持设置表头(水平表头和垂直表头)的文本、图标等。
  5. 信号与槽

    • 提供丰富的信号(如单元格点击、双击、选择变化等),方便开发者响应用户操作。

三、项目演练

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);
}


http://www.kler.cn/a/567580.html

相关文章:

  • JavaScript系列02-函数深入理解
  • 通过统计学视角解读机器学习:从贝叶斯到正则化
  • 华为在不同发展时期的战略选择(节选)
  • Java多线程与高并发专题——深入ReentrantReadWriteLock
  • Python 数据可视化(一)熟悉Matplotlib
  • iOS中的设计模式(六)- 单利模式
  • 问题解决:word导出的pdf图片不清晰?打印机导出的不是pdf,是.log文本文档?
  • 性能测试丨JMeter 分布式加压机制
  • uniapp 阿里云点播 播放bug
  • 目标检测——数据处理
  • 前端清除浮动有哪些方式?
  • 微服务即时通信系统---(七)文件管理子服务
  • 关于延迟任务线程池,Java提供的ScheduledThreadPoolExecutor,Spring提供的ThreadPoolTaskScheduler
  • flutter 专题 八十 Flutter 应用性能检测与优化
  • AUTOSAR整体架构与应用层详解和综合实例
  • 基于fast-whisper模型的语音识别工具的设计与实现
  • 【西瓜书《机器学习》七八九章内容通俗理解】
  • JWT概念及JAVA使用
  • Winbox5怎样设置上网
  • PAT乙级(1026 程序运行时间)C语言超详细解析