You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Qt Creator(C++)如何向TableView动态添加自定义对象并增删数据?

解决方案:自定义模型实现mydata属性与TableView绑定

作为Qt新手,你觉得用QStandardItemModel必须指定行列号来操作数据太繁琐是完全可以理解的——JavaFX的ObservableList确实提供了更直观的方式。不过Qt的模型/视图框架同样能实现类似的便捷操作,核心是自定义一个适配你mydata对象的表格模型,这样就能直接将对象属性映射到列,并且无需手动指定行列号来完成插入、删除操作。

步骤1:改造mydata类,适配Qt属性系统

首先,我们需要给mydata类添加Qt属性声明(Q_PROPERTY),这样自定义模型可以通过Qt的元对象系统便捷地访问对象的属性值。

mydata.h

#ifndef MYDATA_H
#define MYDATA_H

#include <QObject> // 必须继承QObject才能使用元对象系统

class mydata : public QObject
{
    Q_OBJECT
    // 声明每个属性,格式:Q_PROPERTY(类型 属性名 READ 获取函数 WRITE 设置函数)
    Q_PROPERTY(QString Account READ getAccount WRITE setAccount)
    Q_PROPERTY(QString Exchange READ getExchange WRITE setExchange)
    Q_PROPERTY(QString Orderstatus READ getOrderstatus WRITE setOrderstatus)
    Q_PROPERTY(QString Clorid READ getClorid WRITE setClorid)

public:
    explicit mydata(QObject *parent = nullptr);

    // 属性的获取函数
    QString getAccount() const;
    QString getExchange() const;
    QString getOrderstatus() const;
    QString getClorid() const;

    // 属性的设置函数(可选,如果你需要修改属性的话)
    void setAccount(const QString &value);
    void setExchange(const QString &value);
    void setOrderstatus(const QString &value);
    void setClorid(const QString &value);

private:
    QString Account;
    QString Exchange;
    QString Orderstatus;
    QString Clorid;
};

#endif // MYDATA_H

mydata.cpp

#include "mydata.h"

mydata::mydata(QObject *parent) : QObject(parent)
{
    Account = "finsoldts5";
    Exchange = "CME";
    Orderstatus = "Filled";
    Clorid = "CME";
}

QString mydata::getAccount() const
{
    return Account;
}

QString mydata::getExchange() const
{
    return Exchange;
}

QString mydata::getOrderstatus() const
{
    return Orderstatus;
}

QString mydata::getClorid() const
{
    return Clorid;
}

void mydata::setAccount(const QString &value)
{
    Account = value;
}

void mydata::setExchange(const QString &value)
{
    Exchange = value;
}

void mydata::setOrderstatus(const QString &value)
{
    Orderstatus = value;
}

void mydata::setClorid(const QString &value)
{
    Clorid = value;
}

步骤2:自定义表格模型MyTableModel

接下来我们创建一个继承自QAbstractTableModel的模型类,内部维护一个mydata对象的列表,重写必要的虚函数来实现数据映射,同时添加便捷的插入、删除方法。

mytablemodel.h

#ifndef MYTABLEMODEL_H
#define MYTABLEMODEL_H

#include <QAbstractTableModel>
#include <QList>
#include "mydata.h"

class MyTableModel : public QAbstractTableModel
{
    Q_OBJECT
public:
    explicit MyTableModel(QObject *parent = nullptr);

    // 重写模型的核心方法
    int rowCount(const QModelIndex &parent = QModelIndex()) const override;
    int columnCount(const QModelIndex &parent = QModelIndex()) const override;
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
    QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;

    // 自定义的便捷操作方法
    void addData(mydata *data); // 添加一条数据到表格末尾
    void removeLastData(); // 删除最后一行数据
    void removeData(int row); // 删除指定行数据

private:
    QList<mydata*> m_dataList; // 存储所有mydata对象的列表
};

#endif // MYTABLEMODEL_H

mytablemodel.cpp

#include "mytablemodel.h"

MyTableModel::MyTableModel(QObject *parent) : QAbstractTableModel(parent)
{
}

int MyTableModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return m_dataList.size(); // 行数等于数据列表的大小
}

int MyTableModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return 4; // 对应mydata的4个属性
}

QVariant MyTableModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid() || role != Qt::DisplayRole) {
        return QVariant();
    }

    mydata *data = m_dataList.at(index.row());
    switch (index.column()) {
    case 0:
        return data->getAccount();
    case 1:
        return data->getExchange();
    case 2:
        return data->getOrderstatus();
    case 3:
        return data->getClorid();
    default:
        return QVariant();
    }
}

QVariant MyTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (role != Qt::DisplayRole || orientation != Qt::Horizontal) {
        return QVariant();
    }

    // 设置列标题
    switch (section) {
    case 0:
        return "Account";
    case 1:
        return "Exchange";
    case 2:
        return "Order Status";
    case 3:
        return "Clorid";
    default:
        return QVariant();
    }
}

void MyTableModel::addData(mydata *data)
{
    // 通知模型即将插入一行(末尾)
    beginInsertRows(QModelIndex(), m_dataList.size(), m_dataList.size());
    m_dataList.append(data);
    // 通知模型插入完成,视图会自动刷新
    endInsertRows();
}

void MyTableModel::removeLastData()
{
    if (m_dataList.isEmpty()) {
        return;
    }

    // 通知模型即将删除最后一行
    beginRemoveRows(QModelIndex(), m_dataList.size()-1, m_dataList.size()-1);
    delete m_dataList.takeLast(); // 释放内存
    endRemoveRows();
}

void MyTableModel::removeData(int row)
{
    if (row < 0 || row >= m_dataList.size()) {
        return;
    }

    beginRemoveRows(QModelIndex(), row, row);
    delete m_dataList.takeAt(row);
    endRemoveRows();
}

步骤3:在主函数中使用自定义模型

现在我们可以在主函数中创建模型、TableView,并且演示如何添加/删除数据——完全不需要指定行列号,只需要操作MyTableModel的方法即可。

main.cpp

#include <QApplication>
#include <QTableView>
#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>
#include "mytablemodel.h"
#include "mydata.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    // 创建主窗口和布局
    QWidget *window = new QWidget();
    QVBoxLayout *layout = new QVBoxLayout(window);

    // 创建自定义模型
    MyTableModel *model = new MyTableModel();

    // 初始化一些测试数据
    model->addData(new mydata());
    model->addData(new mydata());
    // 创建一个不同的测试数据
    mydata *customData = new mydata();
    customData->setAccount("testAccount123");
    customData->setOrderstatus("Pending");
    model->addData(customData);

    // 创建TableView并设置模型
    QTableView *tableView = new QTableView();
    tableView->setModel(model);
    tableView->horizontalHeader()->setStretchLastSection(true); // 最后一列自适应宽度
    tableView->resizeColumnsToContents(); // 列宽适配内容

    // 创建按钮演示添加/删除操作
    QPushButton *addBtn = new QPushButton("添加新数据");
    QPushButton *removeBtn = new QPushButton("删除最后一行");

    // 绑定按钮点击事件
    QObject::connect(addBtn, &QPushButton::clicked, [=](){
        // 每次点击创建一个新的mydata对象(可以自定义属性值)
        mydata *newData = new mydata();
        static int count = 1;
        newData->setAccount(QString("newAccount%1").arg(count));
        newData->setOrderstatus(count % 2 == 0 ? "Filled" : "Pending");
        count++;
        model->addData(newData);
        tableView->resizeColumnsToContents(); // 重新适配列宽
    });

    QObject::connect(removeBtn, &QPushButton::clicked, [=](){
        model->removeLastData();
    });

    // 添加控件到布局
    layout->addWidget(tableView);
    layout->addWidget(addBtn);
    layout->addWidget(removeBtn);

    window->resize(600, 400);
    window->show();

    return a.exec();
}

关键说明

  1. Qt属性系统:通过Q_PROPERTY声明属性,让模型可以安全地访问mydata的字段,这是Qt模型/视图框架的核心机制之一。
  2. 自定义模型的通知机制beginInsertRowsendInsertRows(以及对应的删除方法)是必须的——它们会通知视图数据发生了变化,视图才会自动刷新,这和JavaFX中ObservableList的自动通知类似。
  3. 内存管理:示例中mydata对象是用new创建的,在删除数据时我们调用了delete来释放内存,如果你不想手动管理内存,可以改用QList<mydata>值类型(需要mydata支持拷贝构造)。

这个实现完全满足你的需求:

  • mydata的四个属性自动映射到表格的4列
  • 添加数据只需要调用addData,自动添加到表格末尾,无需指定行列号
  • 删除数据可以通过removeLastDataremoveData完成,同样无需手动操作行列

内容的提问来源于stack exchange,提问作者hema chandra

火山引擎 最新活动