概述
目录
- 前言
- 效果
- 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)
{
}
记录一些点:
- QTreeView支持shift多选,ctrl点选:
m_treeView->setSelectionMode(QAbstractItemView::ExtendedSelection);
-
更新了数据结构,调用QTreeView的doItemsLayout()刷新界面。
-
QTreeView的selectedIndexs(),获得是QModelIndexList,其中包含了选中行的所有QModelIndex。比如:选中三行,但是每行有两列,那么List中就有6个QModelIndex。
最后
以上就是花痴胡萝卜为你收集整理的Qt 自定义数据结构,重写QTreeView和QAbstractItemModel。前言效果TreeItem:树的数据结构CModel:继承QAbstractItemModelCTreeView:继承QTreeView记录一些点:的全部内容,希望文章能够帮你解决Qt 自定义数据结构,重写QTreeView和QAbstractItemModel。前言效果TreeItem:树的数据结构CModel:继承QAbstractItemModelCTreeView:继承QTreeView记录一些点:所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复