我是靠谱客的博主 花痴胡萝卜,最近开发中收集的这篇文章主要介绍Qt 自定义数据结构,重写QTreeView和QAbstractItemModel。前言效果TreeItem:树的数据结构CModel:继承QAbstractItemModelCTreeView:继承QTreeView记录一些点:,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

目录

  • 前言
  • 效果
  • TreeItem:树的数据结构
  • CModel:继承QAbstractItemModel
  • CTreeView:继承QTreeView
  • 记录一些点:

前言

  一直以来都知道view/model,平时工作也在用,但很多点都很模糊,所以从头写一遍。

效果

在这里插入图片描述

TreeItem:树的数据结构

 数据结构类比较重要的是信息(属性),和对信息的获取、变更的方法。根据自己的需要去定义数据结构即可。
 这里需要实现树结构,所有每个节点的信息有:父节点、子节点列表、信息。
TreeItem.h

#pragma once

#include <QString>
#include <QList>

class TreeItem
{
public:
	TreeItem(TreeItem *parent = nullptr,QString caption = QString(),QString description = QString());
	~TreeItem();

	TreeItem *parent() { return m_parent; }
	void setParent(TreeItem* parent) { this->m_parent = parent; }

	TreeItem *child(int index) { return m_childrens.at(index); }

	int childCount() { return m_childrens.size(); }

	void setCaption(QString caption) { m_caption = caption; }
	QString getCaption() { return m_caption; }

	void setDescription(QString description) { m_description = description; }
	QString getDescription() { return m_description; }

	int indexOf(TreeItem *item) { return m_childrens.indexOf(item); }

	void addItem(TreeItem *item);

private:
	TreeItem*			m_parent;
	QString				m_caption;
	QString				m_description;
	QList<TreeItem *>	m_childrens;
};

TreeItem.cpp

#include "TreeItem.h"

TreeItem::TreeItem(TreeItem * parent, QString caption, QString description )
	:m_parent(parent),m_caption(caption),m_description(description)
{
	if(parent)
		parent->addItem(this);

	m_childrens.clear();
}

TreeItem::~TreeItem()
{
}

void TreeItem::addItem(TreeItem * item)
{
	if (item)
	{
		m_childrens.append(item);
		item->setParent(this);
	}
	else
		Q_ASSERT(0);
}

CModel:继承QAbstractItemModel

必须要重写的五个虚函数:index、parent、rowCount、columnCount、data。针对不同的数据类型,也有不同的实现,这里是针对树结构的实现。
 flag是为了实现可编辑才重写的。非必须。
 setData是为了编辑之后把数据保存到数据结构才重写的。非必须。
CModel.h:

#pragma once
#include <qabstractitemmodel.h>

class TreeItem;

class CModel :
	public QAbstractItemModel
{
public:
	CModel(QObject *parent = nullptr);
	~CModel();
	TreeItem* getTopNode() { return m_topTreeItem; }

	// 通过 QAbstractItemModel 继承
	virtual Q_INVOKABLE QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const override;
	virtual Q_INVOKABLE QModelIndex parent(const QModelIndex & child) const override;
	virtual Q_INVOKABLE int rowCount(const QModelIndex & parent = QModelIndex()) const override;
	virtual Q_INVOKABLE int columnCount(const QModelIndex & parent = QModelIndex()) const override;
	virtual Q_INVOKABLE QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override;
	Qt::ItemFlags flags(const QModelIndex &index) const;
	bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);

private:
	TreeItem *m_topTreeItem;
};


CModel.cpp:

#include "CModel.h"
#include "TreeItem.h"

CModel::CModel(QObject * parent) :QAbstractItemModel(parent)
{
	m_topTreeItem = new TreeItem();
}

CModel::~CModel()
{
}

Q_INVOKABLE QModelIndex CModel::index(int row, int column, const QModelIndex & parent) const
{
	if (!hasIndex(row, column, parent))
		return Q_INVOKABLE QModelIndex();

	TreeItem *parentItem;
	if (parent.isValid())
		parentItem = (TreeItem *)parent.internalPointer();
	else
		parentItem = m_topTreeItem;

	TreeItem *item = parentItem->child(row);

	return createIndex(row, column, item);
}

Q_INVOKABLE QModelIndex CModel::parent(const QModelIndex & child) const
{
	if (!child.isValid())
		return QModelIndex();

	TreeItem *item = (TreeItem *)child.internalPointer();
	TreeItem *parentItem = item->parent();

	if (parentItem == m_topTreeItem)
		return QModelIndex();

	int row = 0;
	if (parentItem->parent())
		row = parentItem->parent()->indexOf(parentItem);

	return createIndex(row,0,parentItem);
}

Q_INVOKABLE int CModel::rowCount(const QModelIndex & parent) const
{
	TreeItem *parentItem;
	if (parent.column() > 0)
		return 0;

	if (parent.isValid())
		parentItem = (TreeItem *)parent.internalPointer();
	else
		parentItem = m_topTreeItem;

	return parentItem->childCount();
}

Q_INVOKABLE int CModel::columnCount(const QModelIndex & parent) const
{
	return 2;
}

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

	TreeItem *item = (TreeItem *)index.internalPointer();
	int colum = index.column();
	switch (role)
	{
	case Qt::EditRole:
	case Qt::DisplayRole:
		if (index.column() == 0)
		{
			return item->getCaption();
		}
		else if (index.column() == 1)
		{
			return item->getDescription();
		}
		break;
	default:
		break;
	}

	return QVariant();
}

Qt::ItemFlags CModel::flags(const QModelIndex & index) const
{
	return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
}

bool CModel::setData(const QModelIndex & index, const QVariant & value, int role)
{
	if (!index.isValid())
		return false;

	TreeItem *item = (TreeItem *)index.internalPointer();
	int column = index.column();
	if (column == 0)
	{
		item->setCaption(value.toString());
		return true;
	}
	else if (column == 1)
	{
		item->setDescription(value.toString());
		return true;
	}
	else
	{
		Q_ASSERT(0);
	}

	return false;
}

CTreeView:继承QTreeView

 在CTreeView中实现一些具体的操作:添加一级节点、添加子节点。(没写删除节点)
 如果要处理每项之前的图标那块,就重写drawBranches。
 如果要处理每行的显示,(没有代理的情况下),重写drawRow。
CTreeView.h

#pragma once
#include <qtreeview.h>

class CModel;
class CTreeView :
	public QTreeView
{
	Q_OBJECT
public:
	CTreeView(QWidget *parent = nullptr);
	virtual ~CTreeView();
	//设置model
	void setTreeModel(QAbstractItemModel *model);
	//设置CModel
	CModel *getCModel() { return m_model; }

public slots:
	//slot:添加一级节点
	void slotAddOneLevelItem();
	//slot:添加子节点
	void slotAddSubItem();

protected:
	void mousePressEvent(QMouseEvent *event);

private:
	//获得选中行的首列QModelIndex
	QModelIndexList getSelectedIndexList();
	//获得选中的行数
	int32_t getSelectedRows();
	void addFolder(QModelIndex index = QModelIndex(), QString caption = QStringLiteral("newFolder"), QString des = QStringLiteral("newDes"));
	
private:
	CModel *m_model;
};


CTreeView.cpp

#include "CTreeView.h"
#include "CModel.h"
#include "TreeItem.h"

#include <QMouseEvent>

CTreeView::CTreeView(QWidget * parent):QTreeView(parent), m_model(nullptr)
{
	//支持多选
	this->setSelectionMode(QAbstractItemView::ExtendedSelection);
}

CTreeView::~CTreeView()
{
}

void CTreeView::setTreeModel(QAbstractItemModel * model)
{
	m_model = dynamic_cast<CModel*>(model);
	if (!m_model)
		Q_ASSERT(0);

	this->setModel(m_model);
}

//slot:添加一级文件夹
void CTreeView::slotAddOneLevelItem()
{
	//判断选中行数
	int32_t selectedRows = this->getSelectedRows();
	if (selectedRows < 0)
	{
		Q_ASSERT(0);
		return;
	}

	//获得根节点
	TreeItem* topNode = getCModel()->getTopNode();
	if (!topNode)
		Q_ASSERT(0);

	//在根节点添加一级节点
	TreeItem* newItem = new TreeItem(topNode, QStringLiteral("新建文件夹"), QStringLiteral("..."));
	
	//刷新界面
	this->doItemsLayout();
}

//slot:添加子节点
void CTreeView::slotAddSubItem()
{
	//判断选中行数
	int32_t selectedRows = this->getSelectedRows();
	if (selectedRows != 1)
	{
		return;
	}

	QModelIndexList selectedList = this->getSelectedIndexList();
	TreeItem* selectedItem = (TreeItem*)selectedList.at(0).internalPointer();
	if (!selectedItem)
	{
		Q_ASSERT(0);
		return;
	}

	TreeItem* newItem = new TreeItem(selectedItem, QStringLiteral("新建文件夹"), QStringLiteral("..."));

	//刷新界面
	this->doItemsLayout();
}

void CTreeView::mousePressEvent(QMouseEvent * event)
{
	QTreeView::mousePressEvent(event);
}

//获得选中行的首列QModelIndex
QModelIndexList CTreeView::getSelectedIndexList()
{
	//获得所有选中的QModelIndex
	QModelIndexList selectedList = this->selectionModel()->selectedIndexes();

	//只留下每行column为0的QModelIndex
	for (int i = 0; i < selectedList.size(); ++i)
	{
		if (selectedList.at(i).column() != 0)
			selectedList.removeOne(selectedList.at(i));
	}

	return selectedList;
}

//获得选中的行数
int32_t CTreeView::getSelectedRows()
{
	QModelIndexList selectedList = this->getSelectedIndexList();

	return selectedList.size();
}

void CTreeView::addFolder(QModelIndex index, QString caption, QString des)
{
	
}

记录一些点:

  1. QTreeView支持shift多选,ctrl点选:
	m_treeView->setSelectionMode(QAbstractItemView::ExtendedSelection);
  1. 更新了数据结构,调用QTreeView的doItemsLayout()刷新界面

  2. QTreeView的selectedIndexs(),获得是QModelIndexList,其中包含了选中行的所有QModelIndex。比如:选中三行,但是每行有两列,那么List中就有6个QModelIndex

最后

以上就是花痴胡萝卜为你收集整理的Qt 自定义数据结构,重写QTreeView和QAbstractItemModel。前言效果TreeItem:树的数据结构CModel:继承QAbstractItemModelCTreeView:继承QTreeView记录一些点:的全部内容,希望文章能够帮你解决Qt 自定义数据结构,重写QTreeView和QAbstractItemModel。前言效果TreeItem:树的数据结构CModel:继承QAbstractItemModelCTreeView:继承QTreeView记录一些点:所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(35)

评论列表共有 0 条评论

立即
投稿
返回
顶部