Qt Model/View

向ai提问:

我想要你写一个Qt程序,使用model和view: view使用QTableView即可,我需要使用model存储4个信息,命令码,发送方地址,接收方地址,报文内容,你可以推荐下使用什么model吗?

方案一:QStandardItemModel(最推荐,上手最快)

这是Qt提供的一个通用模型,使用起来非常方便,适合大多数常规场景。

  • 特点 :它将数据和模型合并在一个类中,通过QStandardItem对象来存储每个单元格的数据。你可以像操作二维数组一样操作它。

  • 优点:API直观,易于理解和使用,适合快速开发。

  • 缺点 :每个单元格都是一个独立的对象,当数据量极大(例如数十万行)时,内存和性能开销会变大。

方案二:继承 QAbstractTableModel(灵活性最高)

如果你的数据来源于自定义的数据结构(例如一个结构体列表),或者需要进行复杂的数据处理,可以选择继承**QAbstractTableModel**来实现自定义模型。

  • 特点:模型本身不存储数据,只作为数据与视图之间的桥梁。你需要自己维护实际的数据存储。

  • 优点:性能最优(无额外对象开销),架构最清晰,数据与界面完全解耦,扩展性最强。

  • 缺点 :需要手动重写**rowCount()columnCount()data()**等几个核心函数,代码量稍多。

方案三:QSqlTableModel(需与数据库交互)

如果你的数据需要持久化存储在数据库中(如SQLite、MySQL ),可以直接使用QSqlTableModel

  • 特点:直接与数据库表关联,模型的操作会自动同步到数据库。

  • 优点:无需手动编写SQL语句进行增删改查,非常方便。

  • 缺点必须依赖数据库,不适合纯内存数据的场景。


总结与建议

模型 推荐场景
QStandardItemModel 数据量不大(< 1万行),快速原型开发,通用场景
QAbstractTableModel 数据量大,数据结构复杂,需要与业务深度绑定
QSqlTableModel 数据需要持久化存储在数据库中

我现在会先用deepseek问一下大体的实现思路,方案的优劣性。

然后让TRAE Work CN来帮我实现一版demo,直接运行看效果。

效果好的话直接引入关键类和程序到项目中。

cpp 复制代码
#ifndef MESSAGETABLEMODEL_H
#define MESSAGETABLEMODEL_H

#include <QAbstractTableModel>
#include <QVector>

struct MessageItem {
    QString commandCode;
    QString senderAddress;
    QString receiverAddress;
    QString content;
};

class MessageTableModel : public QAbstractTableModel
{
    Q_OBJECT

public:
    enum Column {
        CommandCode = 0,
        SenderAddress,
        ReceiverAddress,
        Content,
        ColumnCount
    };

    explicit MessageTableModel(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;

    Qt::ItemFlags flags(const QModelIndex &index) const override;
    bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;

    bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
    bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;

    void addMessage(const MessageItem &item);
    void clear();

private:
    QVector<MessageItem> m_messages;
};

#endif // MESSAGETABLEMODEL_H
cpp 复制代码
#include "messagetablemodel.h"

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

int MessageTableModel::rowCount(const QModelIndex &parent) const
{
    return parent.isValid() ? 0 : m_messages.size();
}

int MessageTableModel::columnCount(const QModelIndex &parent) const
{
    return parent.isValid() ? 0 : ColumnCount;
}

QVariant MessageTableModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid() || index.row() < 0 || index.row() >= m_messages.size())
        return {};

    if (role == Qt::DisplayRole || role == Qt::EditRole) {
        const MessageItem &item = m_messages.at(index.row());
        switch (index.column()) {
        case CommandCode:      return item.commandCode;
        case SenderAddress:    return item.senderAddress;
        case ReceiverAddress:  return item.receiverAddress;
        case Content:          return item.content;
        }
    }

    if (role == Qt::TextAlignmentRole) {
        return Qt::AlignCenter;
    }

    return {};
}

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

    if (orientation == Qt::Horizontal) {
        switch (section) {
        case CommandCode:      return QStringLiteral("命令码");
        case SenderAddress:    return QStringLiteral("发送方地址");
        case ReceiverAddress:  return QStringLiteral("接收方地址");
        case Content:           return QStringLiteral("报文内容");
        }
    }
    return section + 1;
}

Qt::ItemFlags MessageTableModel::flags(const QModelIndex &index) const
{
    if (!index.isValid())
        return QAbstractTableModel::flags(index);
    return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
}

bool MessageTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (!index.isValid() || role != Qt::EditRole)
        return false;

    MessageItem &item = m_messages[index.row()];
    switch (index.column()) {
    case CommandCode:      item.commandCode     = value.toString(); break;
    case SenderAddress:    item.senderAddress   = value.toString(); break;
    case ReceiverAddress:  item.receiverAddress = value.toString(); break;
    case Content:          item.content         = value.toString(); break;
    default: return false;
    }

    emit dataChanged(index, index, {role});
    return true;
}

bool MessageTableModel::insertRows(int row, int count, const QModelIndex &parent)
{
    if (parent.isValid())
        return false;

    beginInsertRows(parent, row, row + count - 1);
    for (int i = 0; i < count; ++i)
        m_messages.insert(row, MessageItem{});
    endInsertRows();
    return true;
}

bool MessageTableModel::removeRows(int row, int count, const QModelIndex &parent)
{
    if (parent.isValid() || row < 0 || row + count > m_messages.size())
        return false;

    beginRemoveRows(parent, row, row + count - 1);
    for (int i = 0; i < count; ++i)
        m_messages.removeAt(row);
    endRemoveRows();
    return true;
}

void MessageTableModel::addMessage(const MessageItem &item)
{
    int row = m_messages.size();
    beginInsertRows(QModelIndex(), row, row);
    m_messages.append(item);
    endInsertRows();
}

void MessageTableModel::clear()
{
    if (m_messages.isEmpty())
        return;
    beginResetModel();
    m_messages.clear();
    endResetModel();
}
cpp 复制代码
#include <QApplication>
#include <QTableView>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QInputDialog>
#include <QHeaderView>
#include <QWidget>

#include "messagetablemodel.h"

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

    auto *model = new MessageTableModel;
    for(int i = 0;i < 200000;i++)
    {
        model->addMessage({"0x01", "0xAA", "0xBB", "Hello World aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"});
        model->addMessage({"0x02", "0xCC", "0xDD", "Request Data bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"});
        model->addMessage({"0x03", "0xEE", "0xFF", "ACK ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"});
    }


    auto *tableView = new QTableView;
    tableView->setModel(model);
    tableView->horizontalHeader()->setStretchLastSection(true);
    tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
    tableView->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed);
    tableView->resizeColumnsToContents();


    auto *mainLayout = new QVBoxLayout;
    mainLayout->addWidget(tableView);

    QWidget window;
    window.setWindowTitle(QStringLiteral("报文模型视图示例"));
    window.resize(700, 400);
    window.setLayout(mainLayout);
    window.show();


    return app.exec();
}

效果蛮好的

相关推荐
Quz2 小时前
QML MouseArea:鼠标拖拽与滚轮缩放
qt·qml
CHPCWWHSU3 小时前
DeepSeek-Harness-Qt将浏览器端Agent装入桌面应用
开发语言·qt
飘忽不定的bug8 小时前
ubuntu20.04交叉编译QT5.15.12(RK3562+ubuntu20.04)
linux·qt·ubuntu
秋田君10 小时前
Qt_QMediaPlayer类与QMediaPlaylist类
开发语言·qt
mengzhi啊10 小时前
QT程序界面自适应1080/2K/4K屏幕。qputenv或者setAttribute
qt
C++ 老炮儿的技术栈10 小时前
Qt5 使用 QPainter 绘制阿基米德螺线
开发语言·c++·windows·qt·代码化
大丑哥1 天前
QT QML 中实现高亮功能
qt
小白不想画工图1 天前
银河麒麟V10系统安装QT5.12
linux·开发语言·qt·银河麒麟
mengzhi啊1 天前
QEventLoop loop配合loop.exec();替代while(1)。电脑cpu占用为0,使用while(1)cpu占用率100%
c++·qt