QT中QTableView+Model+Delegate实现一个demo

发布于:2025-08-01 ⋅ 阅读:(24) ⋅ 点赞:(0)

一、概述

功能: 实现一个查询学生信息的表格,有学号、性别、年龄、班级和分数共5列,针对最后一列分数实现委托代理,要求能编辑和查看该分数列。

QTableView实现视图展示ui

Model负责数据的构造

Delegate是委托,可针对某列数据做自定义扩展

使用的qt控件如下:

  • QTableView
  • StudentTableModel继承自QAbstractTableModel
  • ScoreDelegate继承自QStyledItemDelegate

二、具体代码

studenttablemodel.h

#ifndef STUDENTTABLEMODEL_H
#define STUDENTTABLEMODEL_H

#include <QAbstractTableModel>
#include <QObject>

class StudentTableModel : public QAbstractTableModel
{
    Q_OBJECT
public:
    explicit StudentTableModel(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;
    bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;

    Qt::ItemFlags flags(const QModelIndex &index) const override;

private:
    QVector<QVector<QVariant>> m_data; // 数据存储
};

#endif // STUDENTTABLEMODEL_H

studenttablemodel.cpp

#include "studenttablemodel.h"

StudentTableModel::StudentTableModel(QObject *parent)
    : QAbstractTableModel{parent}
{
    // 初始化示例数据
    m_data = {
        {"1001", "male", 18, "class_01", 85},
        {"1002", "female", 19, "class_02", 92},
        {"1003", "male", 20, "class_03", 78}
    };
}

int StudentTableModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return m_data.size();
}

int StudentTableModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return 5; // 学号、性别、年龄、班级、分数
}

QVariant StudentTableModel::data(const QModelIndex &index, int role) const
{
    if(!index.isValid()) return QVariant();

    if (role == Qt::DisplayRole || role == Qt::EditRole) {
        return m_data[index.row()][index.column()];
    }
    return QVariant();
}

QVariant StudentTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
        switch (section) {
        case 0: return "id";
        case 1: return "sex";
        case 2: return "age";
        case 3: return "class";
        case 4: return "score";
        }
    }
    return QVariant();
}

bool StudentTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (role == Qt::EditRole && index.isValid()) {
        m_data[index.row()][index.column()] = value;
        emit dataChanged(index, index); // 通知视图更新
        return true;
    }
    return false;
}

Qt::ItemFlags StudentTableModel::flags(const QModelIndex &index) const
{
    auto flags = QAbstractTableModel::flags(index);
    if (index.column() == 4) // 分数列可编辑
        flags |= Qt::ItemIsEditable;
    return flags;
}

scoredelegate.h

#ifndef SCOREDELEGATE_H
#define SCOREDELEGATE_H

#include <QObject>
#include <QStyledItemDelegate>

class ScoreDelegate : public QStyledItemDelegate
{
    Q_OBJECT
public:
    explicit ScoreDelegate(QObject *parent = nullptr);

    QWidget *createEditor(QWidget *parent,
                          const QStyleOptionViewItem &option,
                          const QModelIndex &index) const override;

    void setEditorData(QWidget *editor, const QModelIndex &index) const override;
    void setModelData(QWidget *editor,
                      QAbstractItemModel *model,
                      const QModelIndex &index) const override;
};

#endif // SCOREDELEGATE_H
#include "scoredelegate.h"

#include <QSpinBox>

ScoreDelegate::ScoreDelegate(QObject *parent)
    : QStyledItemDelegate{parent}
{}

QWidget *ScoreDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    if (index.column() == 4) { // 仅对分数列生效
        QSpinBox *editor = new QSpinBox(parent);
        editor->setRange(0, 100);
        editor->setFrame(false);
        return editor;
    }
    return QStyledItemDelegate::createEditor(parent, option, index);
}

void ScoreDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    if (index.column() == 4) {
        int value = index.model()->data(index, Qt::EditRole).toInt();
        QSpinBox *spinBox = qobject_cast<QSpinBox*>(editor);
        spinBox->setValue(value);
    } else {
        QStyledItemDelegate::setEditorData(editor, index);
    }
}

void ScoreDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    if (index.column() == 4) {
        QSpinBox *spinBox = qobject_cast<QSpinBox*>(editor);
        spinBox->interpretText();
        model->setData(index, spinBox->value());
    } else {
        QStyledItemDelegate::setModelData(editor, model, index);
    }
}

widget.cpp

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    model = new StudentTableModel(this);
    scoreDelegate = new ScoreDelegate(this);

    ui->tableView->setModel(this->model);
    ui->tableView->setItemDelegateForColumn(4, scoreDelegate);

    // 表格样式设置
    ui->tableView->verticalHeader()->hide();
    ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
    ui->tableView->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked);

    //手动设置show显示
    ui->tableView->show();
}

三、遇到问题总结

1、QTableView展示不出来,model+tableview为局部变量

 当构造函数执行结束时,这两个对象会被自动销毁。即使调用了 tableView.show(),窗口会短暂显示,但对象销毁后视图也随之消失,因此实际看不到表格

    解决方案​:
将 tableView 和 model ​提升为类的成员变量,确保其生命周期与窗口一致:

2、 ​视图未嵌入父窗口布局

问题分析​:

  • 即使解决了生命周期问题,若 tableView 未添加到窗口布局中,它可能因尺寸为0或位置错误而不可见。
  • 你的代码中 tableView 是独立创建的,未关联到 ui 生成的界面布局中。

解决方案​:
将 tableView 添加到窗口的布局管理器中(例如使用 QVBoxLayout):


网站公告

今日签到

点亮在社区的每一天
去签到