my-QT专栏

QAbstrctItemModel+TreeView自定义树

2021-06-22  本文已影响0人  c之气三段

首先需要知道展示基本的树需要重写QAbstrctItemModel继承类的这5个函数。至少完成这个五个函数的实现才会展示数据

 // Header:
    QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;

    // 索引结构
    QModelIndex index(int row, int column,
                      const QModelIndex &parent = QModelIndex()) const override;
    QModelIndex parent(const QModelIndex &index) const override;
    //节点的行列(m,n)
    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;

基于model and view 加上data完成了一个特殊的结构就是数据视图分离这和java中说的MVC相似。
这样的好处是我们可以随意处理自己的数据。

构建模型步骤

1.数据结构Item可以用结构体或者类来定义这个项基本的数据结构。项包含了当前的展示数据,父节点和孩子节点列表。需要定义获取项数据的函数。
TreeItem.h

#ifndef TREEITEM_H
#define TREEITEM_H
#include<QtCore>

class TreeItem
{
public:
    TreeItem();

    QVariant getData() const;
    bool setData(const QVariant &value);
//得到当前节点孩子的数量
    int getChildrenCount() const;
    void addChildren(TreeItem *node);
    TreeItem*getChild(int row);

    TreeItem *getPrent() const;

   //得到当前项的索引
    int getCurrentRow();

private:
    QVariant m_data;
    QList<TreeItem*> m_children;
    TreeItem*m_prent=nullptr;
};

#endif // TREEITEM_H

TreeItem.cpp

#include "TreeItem.h"

TreeItem::TreeItem()
{

}

QVariant TreeItem::getData() const
{
    return m_data;
}

bool TreeItem::setData(const QVariant &value)
{
    if(value.isNull()||value=="")return false;
    if(value.isValid())
    {
      m_data = value;
      return true;
    }
    return false;
}

int TreeItem::getChildrenCount() const
{
    return m_children.count();
}

void TreeItem::addChildren(TreeItem *node)
{
    m_children.append(node);
}

TreeItem *TreeItem::getChild(int row)
{
    return  m_children.at(row);
}

TreeItem *TreeItem::getPrent() const
{
    return m_prent;
}

int TreeItem::getCurrentRow()
{
    if(m_prent)
    return m_prent->m_children.indexOf(const_cast<TreeItem*>(this));
    return 0;
}

2.数据源Data这部分用来组织树的结构同时也可以和文件或数据库交互,数据源通常是单例的。当然案例是内存中的,当也是视图模型分离的。
TreeData.h

#ifndef TREEDATA_H
#define TREEDATA_H

#include"TreeItem.h"
class TreeData
{
public:
    TreeData();
    TreeItem *getRootNode() const;
    static TreeData*getInstence();
private:
    TreeItem *rootNode=nullptr;
};

#endif // TREEDATA_H

TreeData.cpp

#include "TreeData.h"
TreeData::TreeData()
{
    //root
       QString rootData="root";
       rootNode=new TreeItem();
       rootNode->setData(rootData);

   //root child
       QString first="first";
       TreeItem*first_node=new TreeItem();
       first_node->setData(first);
       first_node->setPrent(rootNode);
       rootNode->addChildren(first_node);

       QString first_1="first_1";
       TreeItem*first_node_1=new TreeItem();
       first_node_1->setData(first);
       first_node_1->setPrent(first_node);
       first_node->addChildren(first_node_1);

       QString first_2="first_2";
       TreeItem*first_node_2=new TreeItem();
       first_node_2->setData(first_2);
       first_node_2->setPrent(first_node);
       first_node->addChildren(first_node_2);

  //root child
       QString scond="scond";
       TreeItem*scond_node=new TreeItem();
       scond_node->setData(scond);
       scond_node->setPrent(rootNode);
       rootNode->addChildren(scond_node);

       QString scond_1="scond_1";
       TreeItem*scond_node_1=new TreeItem();
       scond_node_1->setData(scond_1);
       scond_node_1->setPrent(scond_node);
       scond_node->addChildren(scond_node_1);

       QString scond_2="scond_2";
       TreeItem*scond_node_2=new TreeItem();
       scond_node_2->setData(scond_2);
       scond_node_2->setPrent(scond_node);
       scond_node->addChildren(scond_node_2);
}

TreeItem *TreeData::getRootNode() const
{
    return rootNode;
}

TreeData*TreeData::getInstence()
{
    static TreeData treeData;
    return &treeData;
}

3.视图模型,treeview直接获取的数据模型
TreeViewModel.h

#ifndef TREEVIEWMODEL_H
#define TREEVIEWMODEL_H

#include <QAbstractItemModel>
#include"TreeItem.h"
class TreeViewModel : public QAbstractItemModel
{
    Q_OBJECT

public:
    explicit TreeViewModel(QObject *parent = nullptr);

    // Header:
    QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;

    // 索引结构
    QModelIndex index(int row, int column,
                      const QModelIndex &parent = QModelIndex()) const override;
    QModelIndex parent(const QModelIndex &index) const override;
    //节点的行列(m,n)
    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;
private:
    TreeItem*m_rootNode=nullptr;
};

#endif // TREEVIEWMODEL_H

TreeViewModel.cpp

#include "TreeViewModel.h"
#include"TreeData.h"
TreeViewModel::TreeViewModel(QObject *parent)
    : QAbstractItemModel(parent)
{
    m_rootNode=TreeData::getInstence()->getRootNode();
}

QVariant TreeViewModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    Q_UNUSED(section)
    if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
          return m_rootNode->getData();
      return QVariant();
}

QModelIndex TreeViewModel::index(int row, int column, const QModelIndex &parent) const
{
    if(!m_rootNode)
      return QModelIndex();
    if (!this->hasIndex(row, column, parent))
        return QModelIndex();
    if (!parent.isValid())
      return createIndex(row, column, m_rootNode);
    TreeItem *parentItem =static_cast<TreeItem*>(parent.internalPointer());;
    if(parentItem==nullptr)
      return QModelIndex();
    TreeItem *childItem = parentItem->getChild(row);
    if(childItem==nullptr)
        return QModelIndex();
    return createIndex(row, column, childItem);
}

QModelIndex TreeViewModel::parent(const QModelIndex &index) const
{
    if(!m_rootNode)
        return QModelIndex();
    if (!index.isValid())
        return QModelIndex();
    TreeItem* nodeItem = static_cast<TreeItem*>(index.internalPointer()); // get parent node
    nodeItem = nodeItem->getPrent();
    if (nodeItem == nullptr)
        return QModelIndex();
    int row = nodeItem->getCurrentRow(); // get parent index
    return createIndex(row, 0, nodeItem);
}

int TreeViewModel::rowCount(const QModelIndex &parent) const
{
    if (!parent.isValid())
            return 1;
    TreeItem* pNode = static_cast<TreeItem*>(parent.internalPointer());
    return pNode->getChildrenCount();
}

int TreeViewModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    return 1;
}

QVariant TreeViewModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
            return QVariant();
        if (role != Qt::DisplayRole)
            return QVariant();
        TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
        return item->getData();
}

Qt::ItemFlags TreeViewModel::flags(const QModelIndex& index) const
{
    if (!index.isValid())
           return 0;
       return Qt::ItemIsEditable | QAbstractItemModel::flags(index);
}

bool TreeViewModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
    if (role != Qt::EditRole)
            return false;
    if(!index.isValid())
        return false;
        TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
        bool result =item->setData(value);

        if (result)
            emit dataChanged(index, index);
        return result;
}


TreeView.cpp

    TreeViewModel *model=new TreeViewModel(this);
    ui->treeView->setModel(model);

上面是自定义的单列树节点:
效果如下

tree.gif
多列的节点请参考:
https://blog.csdn.net/hp_cpp/article/details/96486104?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162374026016780265484949%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=162374026016780265484949&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_v2~rank_v29-2-96486104.nonecase&utm_term=QT+Treeview&spm=1018.2226.3001.4450
上一篇 下一篇

猜你喜欢

热点阅读