前言:
Qt的模型/视图(Model/View)架构是Qt中一个强大的特性,它允许数据的表示(Model)与数据的展示(View)分离,极大地提高了程序的灵活性和可重用性。自定义模型是Qt开发中的一项重要技能,特别是在处理复杂数据结构或需要特殊数据交互方式时。
一、自定义模型
1、模型相关的类
在Qt中,自定义模型通常意味着你需要从
QAbstractItemModel
或其子类(如QAbstractListModel
或QAbstractTableModel
)派生你的类。这些基类提供了管理数据的基本接口,包括数据的插入、删除、修改以及查询等。
QAbstractItemModel
:这是最通用的模型基类,适用于树形结构的数据。QAbstractListModel
:适用于列表或一维数组类型的数据。QAbstractTableModel
:适用于表格或二维数组类型的数据。
下面是模型类的继承图,如下:
2、自定义模型
2.1、继承QAbstractTableModel
要自定义一个
QAbstractTableModel
,需要从该类派生一个新的类,并在其中实现一些关键的方法。这些方法定义了模型如何与表格视图交互,包括数据的获取、行列的数量、数据项的修改等。如下:
#include <QAbstractTableModel>
class MyModel : public QAbstractTableModel {
Q_OBJECT
public:
// 构造函数、析构函数等
MyModel (QObject *parent = nullptr);
~MyModel ();
// 必须重写的方法
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;
// 可选重写的方法,用于编辑等
Qt::ItemFlags flags(const QModelIndex &index) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
// 可选重写的方法,用于设置表头显示的信息
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
// 自定义方法
void InitData();
private:
// 数据存储,这里以QStringList的QList为例
QVector<QString> m_headers;
QVector<QVector<QString>> m_data;
};
2.2、实现关键方法
需要实现在类中声明的所有方法,下面是关键方法的实现
rowCount
和columnCount
方法应该返回表格的行数和列数。data
方法用于根据索引和角色返回数据。在表格视图中,这通常用于显示数据。flags
方法定义了表格项的属性,如是否可编辑、可选择等。setData
方法用于更新模型中的数据。如果模型是可编辑的,那么这个方法非常重要。headerData
方法设置表头显示的信息。
#include "MyModel.h"
MyModel::MyModel(QObject *parent) : QAbstractTableModel(parent)
{
InitData();
}
MyModel::~MyModel()
{
}
void MyModel::InitData()
{
// 初始化数据
m_headers << "Name" << "Age" << "Sex";
QVector<QString> data1 = { "Alice", "30", "女" };
QVector<QString> data2 = { "Bob", "25", "男" };
QVector<QString> data3 = { "Charlie", "35", "女" };
m_data << data1 << data2 << data3;
}
int MyModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_data.size();
}
int MyModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_headers.size();
}
QVariant MyModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() >= m_data.size() || index.column() >= m_headers.size())
return QVariant();
if (role == Qt::DisplayRole) {
const QVector<QString> &row = m_data[index.row()];
return row[index.column()];
}
return QVariant();
}
bool MyModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (index.isValid() && index.row() < m_data.size() && index.column() < m_headers.size() && role == Qt::EditRole) {
QVector<QString> &row = m_data[index.row()];
row[index.column()] = value.toString();
emit dataChanged(index, index);
return true;
}
return false;
}
QVariant MyModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
return m_headers[section];
}
// 可以默认去除每行的编号
return QVariant();
}
Qt::ItemFlags MyModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return Qt::NoItemFlags;
return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled;
}
2.3、使用自定义模型
自定义模型创建完,可以将这个模型设置为某个表格视图(如
QTableView
)的模型,如下:
// 假设你已经创建了一个MyTableModel的实例叫做model
QTableView *tableView = new QTableView(this);
tableView->setModel(model);