QAbstractItemModel 自定义数据模型

#ifndef CUSTOMITEMMODEL_H
#define CUSTOMITEMMODEL_H

#include <QAbstractItemModel>
#include"CustomItemModel.h"
#include<QDebug>
///至少需要实现 columnCout()、rowCount()、index()、parent()、data()
struct Student
{
	int id;
	QString name;
	int age;
	double score;
	QString  other;

};
class CustomItemModel : public QAbstractItemModel
{
	Q_OBJECT
public:
	explicit CustomItemModel(QObject *parent = nullptr);
	~CustomItemModel();
	// Header:
	virtual  QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
	virtual bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole) override;
	// Basic functionality:
	virtual QModelIndex index(int row, int column,const QModelIndex &parent = QModelIndex()) const override;
	virtual QModelIndex parent(const QModelIndex &index) const override;
	///行数和列数
	virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override;
	virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override;

	virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
	virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
	virtual Qt::ItemFlags flags(const QModelIndex& index) const override;
	// Add data:
	///一次性向表格之中从row位置开始插入count行
	virtual bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
	virtual bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex()) override;
	// Remove data:
	virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
	virtual bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex()) override;




	// Fetch data dynamically:
	virtual bool hasChildren(const QModelIndex &parent = QModelIndex()) const override;
	virtual bool canFetchMore(const QModelIndex &parent) const override;
	virtual void fetchMore(const QModelIndex &parent) override;


public:
	inline QVector<bool >  CheckState()  {
		return m_lastCheckState;
	}

public slots:
	void pushData(int id,QString name, int age,double score, QString other); //向模型添加一个数据
signals:
	void signal_check(const QModelIndex &index, bool checked);

private:
	QVector<Student> m_dataVector ; 
	QList<QString> m_headName;  //储存表头名称
	QVector<QPair<bool, bool>> m_checked;  //储存某个位置是否被勾选
	
	QVector<bool > m_lastCheckState;



};

#endif // CUSTOMITEMMODEL_H

#include "CustomItemModel.h"
#include <QDebug>
#include <QColor>
#include <QFont>
#include <iostream>

CustomItemModel::CustomItemModel(QObject *parent)
	: QAbstractItemModel(parent)
{
	
	Student s1;
	s1.id = 1;
	s1.age = 20;
	s1.name = "Bob";
	s1.score = 97;
	s1.other = QStringLiteral("things");
	m_dataVector.push_back(s1);
	s1.id = 12;
	s1.age = 20;
	s1.name = "Bob";
	s1.score = 97;
	s1.other = QStringLiteral("things");


	m_dataVector.push_back(s1); 
	
	s1.id = 102;
	s1.age = 20;
	s1.name = "Bob";
	s1.score = 97;
	s1.other = QStringLiteral("things");


	m_dataVector.push_back(s1);

	m_headName = { "ID","Name","Age","Score","Other" };
	m_checked.append(QPair<bool, bool>(false, false));
	m_checked.append(QPair<bool, bool>(false, false)); 
	m_checked.append(QPair<bool, bool>(false, false));

	for (size_t i = 0; i < 3; i++)
	{
	   m_lastCheckState.push_back(false);
	}
	

}

CustomItemModel::~CustomItemModel()
{
	
}
/*
返回具有指定方向的标题中给定角色和部分的数据。对于水平标题,节号对应于列号。 同样,对于垂直标题,节号对应于行号。
*/
QVariant CustomItemModel::headerData(int section, Qt::Orientation orientation, int role) const
{

	if (role != Qt::DisplayRole)
		return QVariant();
	if (orientation == Qt::Vertical)
		return QVariant(section);//列标题就是简单的序号
	if (orientation == Qt::Horizontal)
	{
		if (section == 0) 
			return QVariant(m_headName[0]);
		if (section == 1) 
			return QVariant(m_headName[1]);
		if (section == 2)
			return QVariant(m_headName[2]);
		if (section == 3)
			return QVariant(m_headName[3]);
		if (section == 4)
			return QVariant(m_headName[4]);
	}
	return QVariant();
}
/*
设置标题的值。如果标题的数据已更新则返回 true。
重新实现此函数时,必须显式发出 headerDataChanged() 信号。
*/
//section索引 分行 还是列
bool CustomItemModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role)
{
	if (value != headerData(section, orientation, role)) 
	{
		if (role != Qt::EditRole) 
			return false;
		if (orientation == Qt::Vertical) 
			return false;
		if (section == 0) 
			m_headName[0] = value.toString();
		if (section == 1)
			m_headName[1] = value.toString();
		if (section == 2)
			m_headName[2] = value.toString();
		if (section == 3)
			m_headName[3] = value.toString();
		if (section == 4)
			m_headName[4] = value.toString();
		emit headerDataChanged(orientation, section, section);
		return true;
	}
	return false;
}
/*
给每个项创建索引。
对于表格结构,只需向createIndex()函数传递当前数据项所在的行号、列号及使用的数据的指针即可;
*/
QModelIndex CustomItemModel::index(int row, int column, const QModelIndex &parent) const
{
	if (row > m_dataVector.size() - 1 || row < 0) 
		return  QModelIndex();
	if (column >4 || column < 0) 
		return QModelIndex();
	return createIndex(row, column);
}
///返回具有给定索引的模型项的父项。返回无效的 QModelIndex。
QModelIndex CustomItemModel::parent(const QModelIndex &index) const
{
	return QModelIndex();
}
///返回给定父项下的行数
int CustomItemModel::rowCount(const QModelIndex &parent) const
{
	return m_dataVector.size();
}
//返回给定父级的子级的列数。在大多数子类中,列数与父类无关
int CustomItemModel::columnCount(const QModelIndex &parent) const
{
	return 5;
}

bool CustomItemModel::hasChildren(const QModelIndex &parent) const
{
	return false;
}

bool CustomItemModel::canFetchMore(const QModelIndex &parent) const
{
	return false;
}

void CustomItemModel::fetchMore(const QModelIndex &parent)
{
	// FIXME: Implement me!
}
/*
data()函数的返回值决定了视图上应显示的数据,也就是说在界面上用户看到的数据是由该函数返回的,
若返回不当的值,则数据无法正常显示在视图上
data()函数会被视图类调用多次,视图每次都会向data传递一个不同的role(角色)参数值,
然后视图根据data返回的值,设置该role的数据, 因此在设计data函数的返回值时,
需要根据role的不同值返回不同的数据,以使视图正确的显示。
*/
QVariant CustomItemModel::data(const QModelIndex &index, int role) const
{
	if (!index.isValid())//索引是否有效
		return QVariant();
	if (index.row() > m_dataVector.size() - 1 || index.row() < 0 || index.column() < 0 || index.column() > 4)///索引是否在指定范围
		return QVariant();
	Student s = m_dataVector.at(index.row());
	switch (role)
	{

	case Qt::DisplayRole:
	{///"ID","Name","Age","Score","Other" 
		if (index.column() == 0)
		{
			//Student s = m_dataVector.at(index.row());
			return QVariant(s.id);
		}
		if (index.column() == 1)
		{
			///Student s = m_dataVector.at(index.row());
			return QVariant(s.name);
		}
		if (index.column() ==2)
		{
			///Student s = m_dataVector.at(index.row());
			return QVariant(s.age);
		}
		if (index.column() == 3)
		{
			///Student s = m_dataVector.at(index.row());
			return QVariant(s.score);
		}
		if (index.column() == 4)
		{
			///Student s = m_dataVector.at(index.row());
			return QVariant(s.other);
		}
	}
	case Qt::TextAlignmentRole://文本数据的对齐方式,如居左、居中或居右对齐
	{
		return Qt::AlignCenter;
	}
	case Qt::DecorationRole:
	{
		if (index.column() == 0)
			return QColor(255, 0, 0, 255); //Name显示 红色
		if (index.column() == 1) 
			return QColor(0, 255, 0, 255); //Age列显示绿色
		if (index.column() == 2)
		{
          return QColor(255, 255, 0, 255); //Age列显示绿色
		}
	}
	case Qt::ToolTipRole:
	{
		if (index.column() == 0)
			return QString("this is first col");
		if (index.column() == 1)
			return QString("this is second col"); 
		if (index.column() == 2)
			return QString("this is 2 col");
	}
	case Qt::SizeHintRole:
	{
		return QVariant();
	}
	case Qt::FontRole:
	{//可以改变显示数据的字体样式,如大小、粗细等
		QFont font;
		if (index.column() == 0 ? m_checked.at(index.row()).first : m_checked.at(index.row()).second)
		{
			font.setBold(true);
			return font;
		}
		else 
		{
			return font;
		}
	}
	case Qt::BackgroundRole:
	{
		return QVariant();
	}
	case Qt::ForegroundRole:
	{
		return QVariant();
	}
	case Qt::CheckStateRole:  //设置复选框
	{
//#if 0
		if (index.column() == 0)
		{
			if (m_checked.at(index.row()).first)
				return Qt::Checked;
			else 
				return  Qt::Unchecked;
		}
		else
		{
			if (m_checked.at(index.row()).second) 
				return Qt::Checked;
			else 
				return  Qt::Unchecked;
		}
//#endif
	}
	case Qt::UserRole + 1:  //用户自定义角色 预留
	{
		return QVariant();
	}
	default:
		return QVariant();
	}
}

bool CustomItemModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
	if (data(index, role) != value)
	{
		switch (role)
		{
		case Qt::EditRole: ///更新数据
		{
			if (value.toString().isEmpty())
			{
				return true;
			}
			Student s = m_dataVector.at(index.row());
	
			if (index.column() == 0)
			{
				s.id = value.toInt();
			}
			if (index.column() == 1)
			{
				s.name = value.toString();
			}
			if (index.column() ==2)
			{
				s.age = value.toInt();
			}
			if (index.column() == 3)
			{
				s.score = value.toDouble();
			}
			if (index.column() == 4)
			{
				s.other = value.toString();
			}
			m_dataVector.replace(index.row(), s);

			emit dataChanged(index, index, QVector<int>() << role);
			return true;
		}
		case Qt::CheckStateRole:
		{
#if 1
			QPair<bool,bool> cheked = m_checked.at(index.row());
			emit signal_check(index, value.toBool()); ///发送自定义的信号

			if (index.column()==4)
			{
				m_lastCheckState.replace(index.row(), value.toBool());
			}

			if (index.column() == 0)
			{
				m_checked.replace(index.row(), QPair<bool, bool>(value.toBool(), cheked.second));
			}
			else
			{
				m_checked.replace(index.row(), QPair<bool, bool>(cheked.first, value.toBool()));
			}
			emit dataChanged(index, index, QVector<int>() << role);

			return true;
#endif
		}
		default:
			return false;
		}
	}
	return false;
}

Qt::ItemFlags CustomItemModel::flags(const QModelIndex &index) const
{
	if (!index.isValid())
		return Qt::NoItemFlags;

	return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; // FIXME: Implement me!
}

bool CustomItemModel::insertRows(int row, int count, const QModelIndex &parent)
{//一次性向表格之中从row位置开始插入count
	if (row<0 || row>m_dataVector.size() || count < 1) 
		return false;
	beginInsertRows(parent, row, row + count - 1);  ///起始行,终止行

	for (quint8 i = 0; i < count; i++)
	{
		Student  s1;
		s1.age = 0;
		s1.id = 0;
		s1.name = "";
		s1.other = "";
		s1.score = 0;

		QPair<bool, bool> state{ false,false };
		m_dataVector.insert(row + i, s1);
		m_checked.insert(row + i, state);
	}
	endInsertRows();
	return true;
}

bool CustomItemModel::insertColumns(int column, int count, const QModelIndex &parent)
{
	//表格固定是两列,所以此处不做处理
	beginInsertColumns(parent, column, column + count - 1);/// column 起始列 ,终止列
	endInsertColumns();
	return false;
}

///删除行与前面的方法类似
bool CustomItemModel::removeRows(int row, int count, const QModelIndex &parent)
{
	if (row<0 || row>m_dataVector.size() || count < 1) 
		return false;
	beginRemoveRows(parent, row, row + count - 1);
	for (quint8 i = 0; i < count; i++) ///数据也同步删除
	{
		if (m_dataVector.size() == 0) 
			return true;  //判断是否已经删除完,如果已完,提前退出
		m_dataVector.remove(row);
		m_checked.remove(row);
	}
	endRemoveRows();
	return true;
}

bool CustomItemModel::removeColumns(int column, int count, const QModelIndex &parent)
{
	beginRemoveColumns(parent, column, column + count - 1);
	// FIXME: Implement me!
	endRemoveColumns();
	return false;
}

void CustomItemModel:: pushData(int id, QString name, int age, double score, QString other)
{
	Student  s;
	s.id = id;
	s.name = name;
	s.age = age;
	s.score = score;
	s.other = other;

	beginInsertRows(QModelIndex(), m_dataVector.size(), m_dataVector.size());


	m_dataVector.push_back(s);
	m_checked.push_back(QPair<bool, bool>(false, false));

	/*emit dataChanged(
		createIndex(m_dataVector.size() - 1, 0),
		createIndex(m_dataVector.size() - 1, 4),
		QVector<int>() << Qt::DisplayRole << Qt::CheckStateRole
	);*/
	endInsertRows();

}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值