美文网首页my-QT专栏
QAbstrctItemModel+TreeView自定义树

QAbstrctItemModel+TreeView自定义树

作者: c之气三段 | 来源:发表于2021-06-22 22:12 被阅读0次

    首先需要知道展示基本的树需要重写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

    相关文章

      网友评论

        本文标题:QAbstrctItemModel+TreeView自定义树

        本文链接:https://www.haomeiwen.com/subject/beomyltx.html