QTreeView 使用QAbstractItemModel实例

1、TreeViewItem.h

#pragma once

#include <QList>

class TreeViewItem
{
public:

    TreeViewItem(const QList<QVariant>& data, TreeViewItem* parent = NULL);

    ~TreeViewItem();

    void appendChild(TreeViewItem* child);

    void deleteAllChild();

    TreeViewItem* child(int row);

    int childCount() const;

    int columnCount() const;

    QVariant data(int column) const;

    void setParent(TreeViewItem* parent);

    TreeViewItem* parent();

    int row() const;

private:

   TreeViewItem* m_parentItem; 

    QList<TreeViewItem*> m_childItems;

    QList<QVariant> m_itemData;

};

2、TreeViewItem.cpp

#include "TreeViewItem.h"

TreeViewItem::TreeViewItem(const QList<QVariant>& data, TreeViewItem* parent)
{
    this->m_itemData = data;
    this->m_parentItem = parent;
}

TreeViewItem::~TreeViewItem()
{
    this->m_itemData.clear();
    this->m_parentItem = NULL;
}

void TreeViewItem::appendChild(TreeViewItem* child)
{
    child->setParent(this);
    this->m_childItems.append(child);
}

void TreeViewItem::deleteAllChild()
{
    for (int index = 0; index < m_childItems.size(); index++)
    {
        m_childItems[index]->deleteAllChild();
    }
    qDeleteAll(m_childItems);
    m_childItems.clear();
}

TreeViewItem* TreeViewItem::child(int row)
{
    return m_childItems[row];
}

int TreeViewItem::childCount() const
{
    return m_childItems.size();
}

int TreeViewItem::columnCount() const
{
    return m_itemData.size();
}

QVariant TreeViewItem::data(int column) const
{
    return m_itemData[column];
}

void TreeViewItem::setParent(TreeViewItem* parent)
{
    m_parentItem = parent;
}

TreeViewItem* TreeViewItem::parent()
{
    return m_parentItem;
}

int TreeViewItem::row() const
{
    if (!m_parentItem) { return 0; }

    return m_parentItem->m_childItems.indexOf(const_cast<TreeViewItem*>(this));
}

3、TreeViewModel.h

#pragma once

#ifndef TREEVIEWMODEL_H
#define TREEVIEWMODEL_H

#include <QAbstractItemModel>
#include <QObject>
#include <QDebug>
#include "TreeViewItem.h"

#pragma execution_character_set("utf-8")

class TreeViewModel : public QAbstractItemModel
{
    Q_OBJECT

public:
   
    TreeViewModel();

    ~TreeViewModel();

    void setHeaders(const QStringList& headers)
    {
        m_headers = headers;
    }

    void setTreeViewRootItem(TreeViewItem* rootItem)
    {
        m_rootItem = rootItem;
    }

    // 必须要重写的五个函数
    Q_INVOKABLE QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override;

    Q_INVOKABLE QModelIndex parent(const QModelIndex& child) const override;

    Q_INVOKABLE int rowCount(const QModelIndex& parent = QModelIndex()) const override;

    Q_INVOKABLE int columnCount(const QModelIndex& parent = QModelIndex()) const override;

    Q_INVOKABLE QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;


private:

    TreeViewItem* itemFromIndex(const QModelIndex& index) const;

private:

    TreeViewItem* m_rootItem;

    QStringList m_headers;
};

#endif // TREEVIEWMODEL_H
 

4、TreeViewModel.cpp

#include "TreeViewModel.h"

TreeViewModel::TreeViewModel()
{
    m_rootItem = nullptr;
    m_headers.clear();
}

TreeViewModel::~TreeViewModel()
{
    m_rootItem->deleteAllChild();
    m_rootItem = NULL;
}

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

    TreeViewItem* treeItem = itemFromIndex(parent);
    TreeViewItem* child = treeItem->child(row); // 第几行就是第几个子节点,TreeView一般都是一行一个节点的
    if (child) {
        return createIndex(row, column, child);
    }
    else {
        return QModelIndex();
    }

}

// 返回给定项目的父项目
QModelIndex TreeViewModel::parent(const QModelIndex& child) const
{
    if (!child.isValid())
    {
        return QModelIndex();
    }

    TreeViewItem* childItem = static_cast<TreeViewItem*>(child.internalPointer());
    TreeViewItem* parentItem = childItem->parent();

    if (parentItem == m_rootItem)
    {
        return QModelIndex();
    }

    return createIndex(parentItem->row(), 0, parentItem);
}

// 返回给定项目的行数
int TreeViewModel::rowCount(const QModelIndex& parent) const
{
    if (parent.column() > 0)
        return 0;

    TreeViewItem* item = itemFromIndex(parent);
    return item->childCount();
}

// 返回给定项目的列数
int TreeViewModel::columnCount(const QModelIndex& parent) const
{
    if (m_headers.isEmpty())
    {
        // 返回实际的列数 (实际是他返回了0,因为根节点用的是无参的构造),TreeView控件会认为表是空表,不获取数据
        if (parent.isValid())
        {
            return static_cast<TreeViewItem*>(parent.internalPointer())->columnCount();
        }
        else {
            return m_rootItem->columnCount();
        }
    }
    else
    {
        return m_headers.size();
    }
}

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

    TreeViewItem* item = itemFromIndex(index);
    if (role == Qt::DisplayRole)
    {
        return item->data(index.column());
    }
    else if (role == Qt::FontRole)
    {
    }
    else if (role == Qt::TextColorRole) 
    {
    }
    else if (role == Qt::BackgroundRole) 
    {
    }
    else if (role == Qt::TextAlignmentRole)
    {
    }
    return QVariant();
}

// 获取父节点的数据指针,如果parent可用就用parent的节点,如果不可用就用总父节点
TreeViewItem* TreeViewModel::itemFromIndex(const QModelIndex& parent) const
{
    if (parent.isValid())
    {
        // internalPointer: 返回一个void *指针,用于模型将索引与内部数据结构关联起来
        TreeViewItem* item = static_cast<TreeViewItem*>(parent.internalPointer());
        return item;
    }
    return m_rootItem;
}

调用实例:

{

  TreeViewModel* model = new TreeViewModel();

    QStringList headers;
    headers << "1" << "2";
    model->setHeaders(headers);

    QVariantList lstVariant;
    TreeViewItem* pRootItem = new TreeViewItem(lstVariant);
    {
        lstVariant.clear();
        lstVariant << "1" << "第一章";
        TreeViewItem* pItem1 = new TreeViewItem(lstVariant);
        pRootItem->appendChild(pItem1);
    }
    {
        lstVariant.clear();
        lstVariant << "2" << "第二章";
        TreeViewItem* pItem2 = new TreeViewItem(lstVariant);
        pRootItem->appendChild(pItem2);
    }
    model->setTreeViewRootItem(pRootItem);

    ui.treeView->setModel(model);

}

效果如下所示:

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在PyQt6中,可以使用自定义的模型来在QTreeView中显示数据。下面是一个使用自定义模型的示例代码。 ```python from PyQt6.QtCore import QAbstractItemModel, QModelIndex, Qt from PyQt6.QtWidgets import QApplication, QMainWindow, QTreeView class CustomModel(QAbstractItemModel): def __init__(self, data, parent=None): super().__init__(parent) self.rootItem = CustomItem(None, None) self.setupModelData(data, self.rootItem) def setupModelData(self, data, parent): for item in data: parent.appendChild(item) def index(self, row, column, parent=QModelIndex()): if not self.hasIndex(row, column, parent): return QModelIndex() if not parent.isValid(): parentItem = self.rootItem else: parentItem = parent.internalPointer() childItem = parentItem.child(row) if childItem: return self.createIndex(row, column, childItem) else: return QModelIndex() def parent(self, index): if not index.isValid(): return QModelIndex() childItem = index.internalPointer() parentItem = childItem.parent() if parentItem == self.rootItem: return QModelIndex() return self.createIndex(parentItem.row(), 0, parentItem) def rowCount(self, parent=QModelIndex()): if parent.column() > 0: return 0 if not parent.isValid(): parentItem = self.rootItem else: parentItem = parent.internalPointer() return parentItem.childCount() def columnCount(self, parent=QModelIndex()): if parent.isValid(): return parent.internalPointer().columnCount() else: return self.rootItem.columnCount() def data(self, index, role=Qt.ItemDataRole.DisplayRole): if not index.isValid(): return None item = index.internalPointer() if role == Qt.ItemDataRole.DisplayRole: return item.data(index.column()) elif role == Qt.ItemDataRole.TextAlignmentRole: return Qt.AlignmentFlag.AlignVCenter + Qt.AlignmentFlag.AlignLeft def headerData(self, section, orientation, role=Qt.ItemDataRole.DisplayRole): if orientation == Qt.Orientation.Horizontal and role == Qt.ItemDataRole.DisplayRole: return self.rootItem.data(section) def flags(self, index): if not index.isValid(): return Qt.ItemFlag.NoItemFlags return Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable class CustomItem: def __init__(self, data, parent): self.parentItem = parent self.itemData = data self.childItems = [] def appendChild(self, item): self.childItems.append(item) def child(self, row): return self.childItems[row] def childCount(self): return len(self.childItems) def columnCount(self): return len(self.itemData) def data(self, column): return self.itemData[column] def parent(self): return self.parentItem if __name__ == "__main__": app = QApplication([]) window = QMainWindow() treeView = QTreeView(window) data = [ CustomItem(["Item 1"], None), CustomItem(["Item 2"], None) ] model = CustomModel(data) treeView.setModel(model) window.setCentralWidget(treeView) window.resize(500, 500) window.show() app.exec() ``` 在这个示例中,定义了一个`CustomModel`类继承自`QAbstractItemModel`类,并重写了一些必要的方法。同时定义了一个`CustomItem`类作为模型的节点数据。 在`CustomModel`中,`index`方法用于获取给定行列的索引,`parent`方法用于获取给定索引的父索引,`rowCount`和`columnCount`方法用于获取给定索引的行数和列数,`data`方法返回指定索引的数据,`headerData`方法返回给定节的标题数据,`flags`方法定义每个索引的标志。 在主函数中,创建一个自定义模型`CustomModel`的实例,并将数据传递给模型。然后将该模型设置为`QTreeView`的模型,最后显示窗口并进入应用程序的事件循环。 这样,使用自定义模型的QTreeView就可以显示自定义数据了。您可以根据自己的需求扩展并修改此示例代码。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值