一、概述
功能: 实现一个查询学生信息的表格,有学号、性别、年龄、班级和分数共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
):