TreeView 简单使用

news2024/11/26 20:25:40

本文主要介绍 QML 中 TreeView 的基本使用方法,包括:TreeView的适用场景;

控件简介

QML TreeView 是 Qt Quick 中的一个组件,用于显示树形结构的数据。它提供了一种以层次结构方式展示数据的方式,其中每个节点可以包含子节点。

以下是 QML TreeView 的一些关键概念和特点:

  1. Model-View 架构:QML TreeView 遵循 Model-View 架构,其中数据模型(通常是 QAbstractItemModel 的子类)负责提供数据,而视图组件则负责显示和交互。数据模型提供了节点层次结构以及每个节点的数据。
  2. Delegate 委托:TreeView 使用委托来定义每个节点的外观和行为。委托可以自定义,允许您根据需求定制每个节点的呈现方式。
  3. 展开和折叠:TreeView 支持展开和折叠节点的功能。当节点具有子节点时,可以通过点击节点旁边的展开/折叠按钮或者通过编程方式来切换节点的展开状态。
  4. 自定义节点样式:您可以自定义节点的样式,包括文本颜色、背景色、字体、图标等。通过使用不同的委托和属性设置,您可以实现丰富多样的外观效果。
  5. 选择和焦点:TreeView 支持节点的选择和焦点管理。您可以根据需要选择一个或多个节点,并可以通过编程方式操作当前焦点节点。
  6. 事件处理:TreeView 允许处理节点上的各种事件,例如点击、双击、拖放等。您可以根据需要响应这些事件并执行相应的操作。

QML TreeView 在许多应用中都有广泛的应用场景,特别是需要展示层次结构数据的场景。例如,文件浏览器、目录结构、组织架构图等都可以使用 TreeView 来呈现数据并提供交互性。

在这里插入图片描述

QML TreeView 提供了灵活的自定义选项,可以根据需求定制节点的样式和交互行为。通过自定义委托元素,可以为每个节点定义不同的显示方式,以满足特定的设计要求。

前置准备

阅读本节内容前请确保您了解 Qt 中与模型/视图架构相关的内容、与 Python 中调用 QML 相关的内容,包括:

  1. 模型(model)、视图(View)和委托(Delegate)之间的关系。
  2. QML 调用 Python 模型。

如不是特别熟悉,请先阅读《QML 与 Python 交互》,若您想更深入了解,请参阅官方文档《Python-QML integration》、《》。

环境准备:

  • OS:Windows 10 x64
  • Python环境:Python 3.8.x 及以上
  • Python包:PySide6(version 6.3.x 及以上)

使用方法

通过查阅官方文档,我们发现,官方提供了 QML 的 TreeView 的示例代码,但是还需要我们自己实现其对应的 model 部分,下边我们使用 Qt 官方提供的示例代码,给它匹配一个 model ,完成一个完整的节点树,主要我们可以概括为两部分:

  1. 在 Python 文件中定义 TreeView 对应的 model。
  2. 将 model 暴露给 QML ,绑定到 TreeView。

定义 model

在 QML 中,TreeView 使用的 model 必须是继承自 QAbstractItemModel 类的子类,在对 QAbstractItemModel 进行子类实例化时,至少必须实现 index() , parent() , rowCount() , columnCount()data() 。简而言之,就是:在 Python 文件中定义一个类,这个类继承自 QAbstractItemModel ,并且在这个子类中要重写这几个方法。

可选需重写的虚函数:

  • flag——是为了实现可编辑才重写的。
  • setData——是为了编辑之后把数据保存到数据结构才重写的。

要在模型中启用编辑,还必须实现:

  • setData()
  • flags()(要确保返回 ItemIsEditable)

控制模型标题的显示方式,可以实现:

  • headerData()
  • setHeaderData()

在重新实现 setData()setHeaderData() 函数时,必须分别显式地发出 dataChanged()headerDataChanged() 信号。

绑定 model 给 TreeView

在 main.py 中添加这行代码,表示将 treeModel 暴露给 QML 上下文环境中,在 QML 中可以当组件直接调用:

# ...
engine.rootContext().setContextProperty('treeModel', treeModel)
# ...

在 QML 中可以直接使用,如:

// ...
model: treeModel
// ...

这样就完成了 Python 数据模型和 QML 文件的绑定。

完整示例

项目目录结构:

Project
  ├─ main.qml
  ├─ man.py
  └─ TreeModel.py

完整代码:

// main.qml
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts

 Window {
     width: 600
     height: 400
     visible: true

     TreeView {
         anchors.fill: parent
         // The model needs to be a QAbstractItemModel
         model: treeModel

         delegate: Item {
             id: treeDelegate

             implicitWidth: padding + label.x + label.implicitWidth + padding
             implicitHeight: label.implicitHeight * 1.5

             readonly property real indent: 20
             readonly property real padding: 5

             // Assigned to by TreeView:
             required property TreeView treeView
             required property bool isTreeNode
             required property bool expanded
             required property int hasChildren
             required property int depth

             TapHandler {
                 onTapped: treeView.toggleExpanded(row)
             }

             Text {
                 id: indicator
                 visible: treeDelegate.isTreeNode && treeDelegate.hasChildren
                 x: padding + (treeDelegate.depth * treeDelegate.indent)
                 anchors.verticalCenter: label.verticalCenter
                 text: "▶"
                 rotation: treeDelegate.expanded ? 90 : 0
             }

             Text {
                 id: label
                 x: padding + (treeDelegate.isTreeNode ? (treeDelegate.depth + 1) * treeDelegate.indent : 0)
                 width: treeDelegate.width - treeDelegate.padding - x
                 clip: true
                 text: model.display
             }
         }
     }
 }

这是一个使用 QML 语言编写的树形视图(TreeView)的界面定义。让我们逐行解释:

  1. TreeView: 树形视图组件,用于展示树状结构的数据。
  2. anchors.fill: parent: 将 TreeView ​组件的四个边界锚定到父级窗口,使其充满整个窗口空间。
  3. model: treeModel: 指定 TreeView ​使用的数据模型。在这里,treeModel是一个 QAbstractItemModel ​类型的模型,它提供了树形结构的数据。
  4. delegate: 定义了用于绘制每个树节点的委托元素。
  5. implicitWidthimplicitHeight: 定义委托元素的隐式宽度和高度。这些属性决定了每个委托元素的大小。
  6. indentpadding: 定义了缩进和填充的大小,用于控制节点在水平方向上的位置。
  7. TapHandler: 定义了一个用于处理点击事件的处理器。当用户点击委托元素时,将触发onTapped事件。
  8. indicator: 一个用于显示展开/折叠状态的文本元素。根据节点是否是父节点(isTreeNode)和是否有子节点(hasChildren)来决定是否显示。
  9. label: 显示节点的文本内容。根据节点的深度(depth)和是否是父节点来确定水平偏移量。

创建一个带有树形结构的 TreeView,并为每个节点定义了自定义的委托元素。委托元素根据节点的深度和展开状态来显示节点的文本和展开/折叠指示符。你需要提供一个名为treeModel的 QAbstractItemModel 类型的模型来作为 TreeView 的数据源。

# TreeModel.py
from PySide6.QtCore import QAbstractItemModel, QModelIndex, Qt


# 自定义的树形节点类
class TreeNode:
    # 初始化节点数据和父亲节点
    def __init__(self, data, parent=None):
        # 存储节点数据
        self._data = data
        # 存储父节点
        self._parent = parent
        # 存储子节点
        self._children = []

    # 添加一个子节点
    def appendChild(self, child):
        self._children.append(child)

    # 删除一个子节点
    def removeChild(self, item):
        self._children.remove(item)

    # 获取某一行的子节点
    def child(self, row):
        return self._children[row]

    # 获取子节点的个数
    def childCount(self):
        return len(self._children)

    # 获取列数
    def columnCount(self):
        return 1

    # 获取节点某一列的数据
    def data(self, column):
        if column == 0:
            return self._data

    # 获取父节点
    def parent(self):
        return self._parent

    # 获取该节点在父节点中的行号
    def row(self):
        if self._parent:
            return self._parent._children.index(self)

    # 判断节点是否包含子节点
    def hasChildren(self):
        return len(self._children) > 0


# 自定义的树形数据模型
class TreeModel(QAbstractItemModel):
    # 初始化根节点
    def __init__(self, root, parent=None):
        super().__init__(parent)
        # 如果没有传入根节点,则创建一个空的根节点作为根
        self._root = root or TreeNode(None)
        # self._root = root

    # 获取某个节点在模型中的Index
    def index(self, row, column, parent=QModelIndex()):
        if not self.hasIndex(row, column, parent):
            return QModelIndex()

        if not parent.isValid():
            parentItem = self._root
        else:
            parentItem = parent.internalPointer()

        childItem = parentItem.child(row)
        if childItem:
            return self.createIndex(row, column, childItem)
        else:
            return QModelIndex()

    # 获取某个节点的父节点的Index
    def parent(self, index):
        if not index.isValid():
            return QModelIndex()

        childItem = index.internalPointer()
        parentItem = childItem.parent()

        if parentItem == self._root:
            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._root
        else:
            parentItem = parent.internalPointer()

        return parentItem.childCount()

    # 获取列数,这里只有一列
    def columnCount(self, parent=QModelIndex()):
        return 1

    # 获取某个节点的数据
    def data(self, index, role=Qt.DisplayRole):
        if not index.isValid():
            return None

        item = index.internalPointer()
        if role == Qt.DisplayRole:
            return item.data(index.column())

    def flags(self, index):
        if not index.isValid():
            return Qt.NoItemFlags

        return super().flags(index)

这段代码是一个用于创建树形数据模型的类 TreeModel,它是基于 QAbstractItemModel 的子类,用于在 PySide6 中实现树形视图的数据模型。

代码中定义了一个自定义的树形节点类 TreeNode,每个节点包含一个数据项和对父节点和子节点的引用。TreeNode 类提供了一些方法来操作节点的子节点,如添加子节点、删除子节点等。还提供了一些方法用于获取节点的数据、父节点、子节点数量等。

TreeModel 类的构造函数接受一个根节点作为参数,并将其存储在成员变量 _root 中。如果没有传入根节点,则创建一个空的根节点。该类还实现了一些必要的方法,使得树形数据模型能够与视图进行交互。

以下是对 TreeModel 类中重要方法的解读:

  • index(self, row, column, parent=QModelIndex()): 返回指定行和列的节点在模型中的索引。如果索引无效,则返回 QModelIndex()。如果父索引无效,则返回根节点;否则,返回父节点的子节点。
  • parent(self, index): 返回给定索引的父节点的索引。如果索引无效,则返回 QModelIndex()。如果父节点是根节点,则返回无效索引;否则,返回父节点的索引。
  • rowCount(self, parent=QModelIndex()): 返回给定父索引下的子节点数量。如果父索引的列数大于 0,则返回 0。如果父索引无效,则返回根节点的子节点数量;否则,返回父节点的子节点数量。
  • columnCount(self, parent=QModelIndex()): 返回模型中的列数,这里固定为 1。
  • data(self, index, role=Qt.DisplayRole): 返回给定索引处节点的数据。如果索引无效,则返回 None。如果角色是 Qt.DisplayRole,则返回节点的数据。
  • flags(self, index): 返回给定索引的标志。如果索引无效,则返回 Qt.NoItemFlags,表示没有任何标志。
# main.py
from PySide6.QtCore import QUrl
from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import QQmlApplicationEngine
from TreeModel import TreeModel,TreeNode
import sys


if __name__ == '__main__':

    # 创建树形结构
    rootItem = TreeNode("root")
    childItem1 = TreeNode("child1", rootItem)
    childItem2 = TreeNode("child2", rootItem)
    childItem3 = TreeNode("child3", rootItem)
    subChildItem1 = TreeNode("sub_child1", childItem1)
    subChildItem2 = TreeNode("sub_child2", childItem1)

    rootItem.appendChild(childItem1)
    rootItem.appendChild(childItem2)
    rootItem.appendChild(childItem3)
    childItem1.appendChild(subChildItem1)
    childItem1.appendChild(subChildItem2)

    # 创建树形数据模型
    treeModel = TreeModel(rootItem)

    # 启动
    app = QGuiApplication([])
    engine = QQmlApplicationEngine()
    engine.rootContext().setContextProperty('treeModel', treeModel)
    engine.load(QUrl.fromLocalFile('main.qml'))
    engine.quit.connect(app.quit)
    sys.exit(app.exec())

这是一个使用 PySide6 构建的应用程序的入口点 main.py。它创建了一个树形结构,并将其与自定义的树形数据模型 TreeModel 结合使用,最后通过 Qt Quick(QML)界面进行展示。

  • 首先,代码导入了必要的 PySide6 模块和类,以及自定义的 TreeModelTreeNode 类。
  • if __name__ == '__main__': 块中,首先创建了树形结构。根节点是一个名为 “root” 的节点,然后创建了几个子节点,并将它们作为根节点的子节点。子节点也可以有它们自己的子节点。
  • 接下来,通过将根节点传递给 TreeModel 类的构造函数,创建了一个树形数据模型 treeModel
  • 之后,创建了 QGuiApplication 实例 app,用于启动应用程序。
  • 创建了 QQmlApplicationEngine 实例 engine,用于加载和运行 QML 界面。
  • 通过 engine.rootContext().setContextProperty('treeModel', treeModel)treeModel 设置为 QML 上下文属性,以便在 QML 中可以访问该树形数据模型。
  • 使用 engine.load(QUrl.fromLocalFile('main.qml')) 加载 QML 文件,该文件定义了应用程序的界面。
  • 最后,通过 engine.quit.connect(app.quit)enginequit 信号连接到 appquit 槽,以便在关闭应用程序时能够正确退出。
  • 最后使用 sys.exit(app.exec()) 启动应用程序的事件循环。

运行命令:

python main.py

未实现

  • 双击编辑节点

参考

[1].TreeView QML Type.[EB/OL].[2023-6-15].https://doc.qt.io/qt-6/qml-qtquick-treeview.html

[2].QAbstractItemModel.[EB/OL].[2023-6-15].https://doc.qt.io/qtforpython-6/PySide6/QtCore/QAbstractItemModel.html#PySide6.QtCore.PySide6.QtCore.QAbstractItemModel

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/651216.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ESP32学习之定时器和PWM

一.定时器代码如下&#xff1a; #include <Arduino.h>hw_timer_t *timer NULL; int interruptCounter 0;// 函数名称&#xff1a;onTimer() // 函数功能&#xff1a;中断服务的功能&#xff0c;它必须是一个返回void&#xff08;空&#xff09;且没有输入参数的函数 //…

【动态规划】路径问题

冻龟算法系列之路径问题 文章目录 【动态规划】路径问题1. 不同路径1.1 题目解析1.2 算法原理1.2.1 状态表示1.2.2 状态转移方程1.2.3 初始化1.2.4 填表顺序1.2.5 返回值 1.3 编写代码 2. 不同路径Ⅱ2.1 题目解析2.2 算法原理2.2.1 状态表示2.2.2 状态转移方程2.2.3 初始化2.2.…

性能测试学习之数据驱动性能测试

了解数据驱动测试理念、能够如何在jmeter中用多种方式实现数据驱动测试。 知识点&#xff1a;字符串拼接、计数器、循环控制器 1. 数据驱动的理念 1.1 定义 从数据文件中读取测试数据,驱动测试过程的一-种测试方法数据驱动可以理解为更高级的参数化 1.2 特点 测试数据与测试…

【Linux】socket 编程(socket套接字介绍、字节序、socket地址、IP地址转换函数、套接字函数、TCP通信实现)

目录 1、socket套接字介绍2、字节序简介字节序转换函数 3、socket地址专用socket地址 4、IP地址转换函数5、套接字函数6、TCP通信实现&#xff08;服务器端和客户端&#xff09; 橙色 1、socket套接字介绍 所谓套接字&#xff0c;就是对网络中不同主机上的应用进程之间进行双…

深入理解深度学习——Transformer:整合编码器(Encoder)和解码器Decoder)

分类目录&#xff1a;《深入理解深度学习》总目录 相关文章&#xff1a; 注意力机制&#xff08;Attention Mechanism&#xff09;&#xff1a;基础知识 注意力机制&#xff08;Attention Mechanism&#xff09;&#xff1a;注意力汇聚与Nadaraya-Watson核回归 注意力机制&…

国内唯一可以在本地搭建Stable Diffusion WebUI教程-安装时无需魔法安装全程流畅到尖叫

Stable Diffusion是什么 Stable Diffusion简称SD是一款Ai图片生成工具。“输入几句话,生成精美图片。” 比如说我一开头这幅图片就是用的SD生成的。 我在我的“ChatGPT让我变成了“超人”-如何提升团队30%效能质量提高100%的阶段性总结报告”里提到过midjourney,但是midjou…

使用Google工具类Guava自定义一个@Limiter接口限流注解

在Springboot中引用RateLimiter工具类依赖 <dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>30.1-jre</version> </dependency> 需要注意的是&#xff0c;Guava 的不同版本可能会有…

新手第一次做性能测试?性能测试流程详全,从需求到报告一篇打通

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、确认需求 确定…

3、互联网行业及产品经理分类

上一篇文章&#xff1a;2、产品经理的工作内容_阿杰学编程的博客-CSDN博客 1、产品经理分类 我们把产品经理划分成这样两个大的类型&#xff0c;一个是传统行业的&#xff0c;一个是互联网行业的。这个简单了解一下就行。 这个里面会发现绝大多数也是体育劳动&#xff0c;你比…

软件测试岗位都是女孩子在做吗?

听我一朋友说&#xff0c;测试岗位基本都是女孩子做。” 不知道是不是以前“软件测试岗”给人印象是“不需要太多技术含量”的错觉&#xff0c;从而大部分外行认为从业软件测试的人员中女生应占了大多数。比如有人就觉得&#xff1a;软件测试主要是细心活&#xff0c;所以女生…

2023 年各大互联网公司常见面试题(Java 岗)汇总

很多人都说今年对于 IT 行业根本没有所谓的“金三银四”“金九银十”。在各大招聘网站或者软件上不管是大厂还是中小公司大多都是挂个招聘需求&#xff0c;实际并不招人&#xff1b;在行业内的程序员基本都已经感受到了任老前段时间口中所谓的“寒气”。 虽然事实确实是如此&a…

30个接口自动化测试面试题,赶紧收藏

1. 什么是接口自动化测试&#xff1f; 答&#xff1a;接口自动化测试是指使用自动化工具对接口进行测试&#xff0c;验证接口的正确性、稳定性和性能等方面的指标。2. 为什么要进行接口自动化测试&#xff1f; 答&#xff1a;接口自动化测试可以提高测试效率&#xff0c;减少人…

新能源行业如何进行数据防泄漏

客户情况 某新能源电池企业专业从事于新能源锂离子动力电池和储能电池的研发、生产和销售&#xff0c;具备电芯、模组、BMS及Pack的完整资源开发能力。公司致力于通过持续不断地改进电池技术&#xff0c;为全球锂离子动力和储能领域提供数字化精准高效的新能源解决方案。 该企…

Nautilus Chain 主网上线在即,一文盘点该生态即将上线的项目

Nautilus Chain 是行业内第一个并行化&#xff0c;且运行速度最快 EVM Rollup 的L3扩容方案&#xff0c;作为首个模块化链&#xff0c;存储、计算、共识等都在不同的模块中&#xff0c;意味着其能够获得更高的可拓展性与扩容能力&#xff0c;并在Layer2的基础上进一步提升了网络…

SpringCloud Alibaba-Sentinel

SpringCloud Alibaba-Sentinel 1. Sentinel核心库1.1 Sentinel介绍1.2 Sentinel核心功能1.2.1 流量控制1.2.2 熔断降级 2 Sentinel 限流熔断降级2.1 SentinelResource定义资源2.1.1 blockHandler/blockHandlerClass2.1.2 fallback/fallbackClass2.1.3 defaultFallback 2.2 Sent…

2、产品经理的工作内容

上一篇文章&#xff1a;1、产品经理的宏观定义_阿杰学编程的博客-CSDN博客 接下来这个章节里&#xff0c;我们有三个目标。 第一个通过案例&#xff0c;大家要了解一下产品经理的一个主要的工作内容。 第二个理解产品经理的一个重要性。 第三个我们要熟悉一下MVP的概念&…

Vue实战笔记(四) 引入Mavon Editor

大家好&#xff0c;我是半虹&#xff0c;这篇文章来讲如何在 Vue 中引入 Mavon Editor \text{Mavon Editor} Mavon Editor 1、背景介绍 在上篇文章中&#xff0c;我们介绍过如何在 Vue 中引入富文本编辑器 Quill Editor \text{Quill Editor} Quill Editor 在这篇文章中&…

433/315接收芯片 XL520,SOP8封装,适用于低功耗要求产品

XL520是一款高集成度、 低功耗的单片ASK/0OK射频接收芯片。高频信号接收功能全部集成于片内以达到用最少的外围器件和最低的成本获得最可靠的接收效果。 XL520接收芯片为SOP8封装&#xff0c;正常工作电压范围2.0~5.5V&#xff0c;正常工作电流3.0~3.2mA&#xff0c;启动时间2…

pdf可以转换为word文档吗?分享这两个方法给大家!

PDF 是一种常见的文件格式&#xff0c;用于可靠地显示和共享文档。然而&#xff0c;当需要编辑或重用 PDF 内容时&#xff0c;将其转换为可编辑的 Word 文档是一个常见的需求。在本文中&#xff0c;我们将介绍两种方法&#xff0c;以帮助您将 PDF 转换为 Word 文档&#xff0c;…

SpringBoot+Bootstrap图书馆管理系统

主要功能 管理员权限登录&#xff1a; ①管理员拥有最高权限&#xff0c;可以分配角色&#xff0c;使不同角色&#xff08;教师、学生等&#xff09;登录显示不同界面的效果 ②首页、系统设置&#xff1a;菜单管理、角色管理、用户管理、日志管理、数据备份、违规统计、占座统…