30、QStandardItemModel 和 QTableView---------Model/View模型视图

QStandardItemModel 和 QTableView

概念和方法

QStandardItemModel 是以项为基本数据单元的模型类,每个项是一个 QStandardItem 对象。

使用时需包含<QMainWindow>和<QStandardItem>头文件

这部分的方法和内容比较庞杂,快速过一遍,然后零帧起手做个案例,带着大家理解一下。

●设置行数和列数 QStandardItemModel 以二维数组的形式存储项数据,所以可以设置行数和列数。

cpp 复制代码
void setRowCount(int rows) //设置数据模型的行数
void setColumnCount(int columns) //设置数据模型的列数

如果设置的列数大于 1,模型就是表格模型;如果设置的列数为 1,模型就可以看作列表模型。

  • 设置项
cpp 复制代码
void setItem(int row, int column, QStandardItem *item)
void setItem(int row, QStandardItem *item) //用于列表模型
  • 获取项
cpp 复制代码
QStandardItem *item(int row, int column = 0) //根据行号和列号返回项
QStandardItem *itemFromIndex(const QModelIndex &index) //根据模型索引返回项

//函数 indexFromItem()根据项返回其模型索引,其定义如下:
QModelIndex indexFromItem(const QStandardItem *item)
  • 添加行或列
cpp 复制代码
void appendRow(const QList<QStandardItem *> &items) //用于表格模型
void appendRow(QStandardItem *item) //用于列表模型
  • 插入行或列
cpp 复制代码
void insertRow(int row, const QList<QStandardItem *> &items) //用于表格模型
void insertRow(int row, QStandardItem *item) //用于列表模型

案例学习

实现表格数据展示 demo, 如下图所示

开发讲解

1 初步实现

为了实现QTableview和QStandarditemModel的组合,我们在MainWindow中添加成员tableView和model

cpp 复制代码
class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
    //用表格的方式展现数据
    QTableView *tableView;
    //用标准模型基类存储数据
    QStandardItemModel *model;
};

实现构造函数

cpp 复制代码
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    // 设置窗口标题和大小
    setWindowTitle("QStandardItemModel 与 QTableView 教学案例");
    resize(600, 400);
    // 创建表格视图
    tableView = new QTableView(this);
    // 创建模型
    model = new QStandardItemModel(this);
    // 设置表格视图为中心部件
    this->setCentralWidget(tableView);
    // 初始化模型
    model->setHorizontalHeaderLabels({"姓名", "年龄", "职业"});

    // 添加数据
    QList<QStringList> data = {
        {"张三", "25", "工程师"},
        {"李四", "30", "设计师"},
        {"王五", "28", "教师"},
        {"赵六", "22", "学生"}
    };

    for (const QStringList &rowData : data) {
        QList<QStandardItem*> items;
        for (const QString &field : rowData) {
            QStandardItem *item = new QStandardItem(field);
            //设置文字居中
            item->setTextAlignment(Qt::AlignCenter);
            items.append(item);
        }
        model->appendRow(items);
    }

    // 设置模型到视图
    tableView->setModel(model);

    // 设置列宽自适应内容
    tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);

    // 允许编辑
    tableView->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked);

    // 启用排序功能
    tableView->setSortingEnabled(true);

}

运行后可以看到通过tableview和model组合,可以实现显示表格数据显示

2 实现增删

我们在MainWindow中增加槽函数的声明,以及新增两个按钮

cpp 复制代码
private slots:
    //增加行
    void insertRow();
    //删除行
    void deleteRow();
private:
    QPushButton *insertButton;
    QPushButton *deleteButton;

完善MainWindow的构造函数列表,将model, tableview, 以及按钮的创建放在构造列表中,注意原来在构造函数中创建的要删除

cpp 复制代码
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    tableView(new QTableView(this)),
    model(new QStandardItemModel(this)),
    insertButton(new QPushButton("插入行",this)),
    deleteButton(new QPushButton("删除行",this)){
        //...省略
    }

另外我们需要创建一个QWidget用来做中心部件的显示,将原来tableview设为中心部件的逻辑注释掉,

并且基于中心部件创建一个垂直布局,

垂直布局里放入tableview和一个水平布局,水平布局里再加入两个按钮。

cpp 复制代码
// 创建一个中心widget
QWidget *centralWidget = new QWidget(this);
// 基于中心widget创建垂直布局作为主布局
QVBoxLayout *mainLayout = new QVBoxLayout(centralWidget);
// 向布局中加入tableview
mainLayout->addWidget(tableView);
// 创建按钮布局为水平布局
QHBoxLayout *buttonLayout = new QHBoxLayout();
// 加个伸缩因子,也就是弹簧,保证按钮被挤压到右侧
buttonLayout->addStretch(); // 右对齐按钮
//添加插入按钮
buttonLayout->addWidget(insertButton);
//添加删除按钮
buttonLayout->addWidget(deleteButton);
//将按钮布局加入到主布局里
mainLayout->addLayout(buttonLayout);
//最后设置中心部件为中心widget
setCentralWidget(centralWidget);

// 连接信号与槽
connect(insertButton, &QPushButton::clicked, this, &MainWindow::insertRow);
connect(deleteButton, &QPushButton::clicked, this, &MainWindow::deleteRow);

实现插入行的逻辑

cpp 复制代码
void MainWindow::insertRow()
{
    // 获取当前行数
    int row = model->rowCount();

    // 可以选择在特定位置插入,这里选择在末尾插入
    QList<QStandardItem*> items;
    // 提示用户输入新行的数据
    bool ok;
    //获取用户姓名
    QString name = QInputDialog::getText(this, "插入行", "请输入姓名:", QLineEdit::Normal, "", &ok);
    if (!ok || name.isEmpty()) return;
    //获取用户年龄
    QString age = QInputDialog::getText(this, "插入行", "请输入年龄:", QLineEdit::Normal, "", &ok);
    if (!ok || age.isEmpty()) return;
    //获取用户职业
    QString profession = QInputDialog::getText(this, "插入行", "请输入职业:", QLineEdit::Normal, "", &ok);
    if (!ok || profession.isEmpty()) return;

    auto name_item = new QStandardItem(name);
    name_item->setTextAlignment(Qt::AlignCenter);

    auto age_item = new QStandardItem(age);
    age_item->setTextAlignment(Qt::AlignCenter);

    auto profession_item = new QStandardItem(profession);
    profession_item->setTextAlignment(Qt::AlignCenter);

    items.append(name_item);
    items.append(age_item);
    items.append(profession_item);

    model->appendRow(items);

    // 可选:自动调整列宽
    tableView->resizeColumnsToContents();
}

实现删除逻辑

cpp 复制代码
//删除行
void MainWindow::deleteRow()
{
    // 获取当前选中的行
     QModelIndexList selectedIndexes = tableView->selectionModel()->selectedRows();
     if (selectedIndexes.isEmpty()) {
         QMessageBox::warning(this, "删除行", "请先选择要删除的行!");
         return;
     }

     // 确认删除
     auto reply = QMessageBox::question(this, "删除行", "确定要删除选中的行吗?",
                                       QMessageBox::Yes|QMessageBox::No);
     // 取消则返回
     if (reply != QMessageBox::Yes) {
         return;
     }

     QList<int> rows;
     //selectedIndexes存储的时索引列表,可以根据索引获取行号
     for(const QModelIndex& index: selectedIndexes){
        //根据ModelIndex获取行号, 放入列表
         rows.append(index.row());
     }

     //对行号从大到小排序,因为删除要从下往上删除
     //从行号大的向上删除,保证其他待删行号不会受影响
     //greater为仿函数,接受两个参数实现从大到小排序
     std::sort(rows.begin(),rows.end(),std::greater<int>());

     // 删除选中的行,从后往前删
     for(auto row: rows){
        model->removeRow(row);
     }
}
相关推荐
maxmaxma2 小时前
ROS2机器人少年创客营:Python第二课
c++·python·机器人
山栀shanzhi2 小时前
FFmpeg 实战:RGB 裸流编码成 MP4,全流程详解(含源码
c++·ffmpeg
Yupureki2 小时前
《Linux系统编程》20.常见程序设计模式
linux·服务器·c语言·c++·单例模式·建造者模式·责任链模式
sycmancia2 小时前
C++——Qt中的消息处理
开发语言·qt
誰能久伴不乏2 小时前
给开发板装上嘴巴与耳朵:i.MX6ULL 裸机串口 (UART) 驱动终极指南
arm开发·c++·单片机·嵌入式硬件·arm
biter down2 小时前
深入浅出 C++ string 类:从原理到实战
开发语言·c++
Lhan.zzZ3 小时前
Qt多线程数据库操作:安全分离连接,彻底解决段错误
数据库·c++·qt·安全
小樱花的樱花3 小时前
C++引用:高效编程的技巧
开发语言·数据结构·c++·算法
Yupureki3 小时前
《算法竞赛从入门到国奖》算法基础:动态规划-最长子序列
c语言·c++·算法·动态规划