解决方案

TreeView 简单使用

seo靠我 2023-09-23 12:59:37

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

控件简介

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

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

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

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

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

前置准备

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

模型(model)、视图(View)和委托(Delegate)之间的关系。QML 调用 Python 模型SEO靠我

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

环境准备:

OS:Windows 10 x64PytSEO靠我hon环境:Python 3.8.x 及以上Python包:PySide6(version 6.3.x 及以上)

使用方法

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

在 Python 文件中定义 TSEO靠我reeView 对应的 model。将 model 暴露给 QML ,绑定到 TreeView。

定义 model

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

可选需重写的虚函数:

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

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

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

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

headerData()setHeaderData()

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

绑定 model 给 TreeView

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

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

在 QSEO靠我ML 中可以直接使用,如:

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

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

完整示例

项目目录结构:SEO靠我

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

完整代码:

// main.qml import QtQuick import QtQSEO靠我uick.Controls import QtQuick.LayoutsWindow {width: 600height: 400visible: trueTreeView {anchSEO靠我ors.fill: parent// The model needs to be a QAbstractItemModelmodel: treeModeldelegate: Item {id: treSEO靠我eDelegateimplicitWidth: padding + label.x + label.implicitWidth + paddingimplicitHeight: label.impliSEO靠我citHeight * 1.5readonly property real indent: 20readonly property real padding: 5// Assigned to by TSEO靠我reeView:required property TreeView treeViewrequired property bool isTreeNoderequired property bool eSEO靠我xpandedrequired property int hasChildrenrequired property int depthTapHandler {onTapped: treeView.toSEO靠我ggleExpanded(row)}Text {id: indicatorvisible: treeDelegate.isTreeNode && treeDelegate.hasChildrenx: SEO靠我padding + (treeDelegate.depth * treeDelegate.indent)anchors.verticalCenter: label.verticalCentertextSEO靠我: "▶"rotation: treeDelegate.expanded ? 90 : 0}Text {id: labelx: padding + (treeDelegate.isTreeNode ?SEO靠我 (treeDelegate.depth + 1) * treeDelegate.indent : 0)width: treeDelegate.width - treeDelegate.paddingSEO靠我 - xclip: truetext: model.display}}}}

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

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

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

# TreeModel.py from PySide6.QtCore import QAbstractItemModel, QModelIndex, Qt# 自SEO靠我定义的树形节点类 class TreeNode:# 初始化节点数据和父亲节点def __init__(self, data, parent=None):# 存储节点数据self._daSEO靠我ta = data# 存储父节点self._parent = parent# 存储子节点self._children = []# 添加一个子节点def appendChild(self, child)SEO靠我:self._children.append(child)# 删除一个子节点def removeChild(self, item):self._children.remove(item)# 获取某一行SEO靠我的子节点def child(self, row):return self._children[row]# 获取子节点的个数def childCount(self):return len(self._cSEO靠我hildren)# 获取列数def columnCount(self):return 1# 获取节点某一列的数据def data(self, column):if column == 0:returnSEO靠我 self._data# 获取父节点def parent(self):return self._parent# 获取该节点在父节点中的行号def row(self):if self._parent:rSEO靠我eturn self._parent._children.index(self)# 判断节点是否包含子节点def hasChildren(self):return len(self._childrenSEO靠我) > 0# 自定义的树形数据模型 class TreeModel(QAbstractItemModel):# 初始化根节点def __init__(self, root, parenSEO靠我t=None):super().__init__(parent)# 如果没有传入根节点,则创建一个空的根节点作为根self._root = root or TreeNode(None)# self._SEO靠我root = root# 获取某个节点在模型中的Indexdef index(self, row, column, parent=QModelIndex()):if not self.hasIndexSEO靠我(row, column, parent):return QModelIndex()if not parent.isValid():parentItem = self._rootelse:parentSEO靠我Item = parent.internalPointer()childItem = parentItem.child(row)if childItem:return self.createIndexSEO靠我(row, column, childItem)else:return QModelIndex()# 获取某个节点的父节点的Indexdef parent(self, index):if not inSEO靠我dex.isValid():return QModelIndex()childItem = index.internalPointer()parentItem = childItem.parent()SEO靠我if parentItem == self._root:return QModelIndex()return self.createIndex(parentItem.row(), 0, parentISEO靠我tem)# 获取某个节点的子节点个数def rowCount(self, parent=QModelIndex()):if parent.column() > 0:return 0if not parSEO靠我ent.isValid():parentItem = self._rootelse:parentItem = parent.internalPointer()return parentItem.chiSEO靠我ldCount()# 获取列数,这里只有一列def columnCount(self, parent=QModelIndex()):return 1# 获取某个节点的数据def data(self, SEO靠我index, role=Qt.DisplayRole):if not index.isValid():return Noneitem = index.internalPointer()if role SEO靠我== Qt.DisplayRole:return item.data(index.column())def flags(self, index):if not index.isValid():retuSEO靠我rn Qt.NoItemFlagsreturn super().flags(index)

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

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

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

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

index(self, row, column, paSEO靠我rent=QModelIndex()): 返回指定行和列的节点在模型中的索引。如果索引无效,则返回 QModelIndex()。如果父索引无效,则返回根节点;否则,返回父节点的子节点。parent(sSEO靠我elf, index): 返回给定索引的父节点的索引。如果索引无效,则返回 QModelIndex()。如果父节点是根节点,则返回无效索引;否则,返回父节点的索引。rowCount(self, parSEO靠我ent=QModelIndex()): 返回给定父索引下的子节点数量。如果父索引的列数大于 0,则返回 0。如果父索引无效,则返回根节点的子节点数量;否则,返回父节点的子节点数量。columnCounSEO靠我t(self, parent=QModelIndex()): 返回模型中的列数,这里固定为 1。data(self, index, role=Qt.DisplayRole): 返回给定索引处节点的数据SEO靠我。如果索引无效,则返回 None。如果角色是 Qt.DisplayRole,则返回节点的数据。flags(self, index): 返回给定索引的标志。如果索引无效,则返回 Qt.NoItemFlaSEO靠我gs,表示没有任何标志。 # main.py from PySide6.QtCore import QUrl from PySide6.QtGui imSEO靠我port QGuiApplication from PySide6.QtQml import QQmlApplicationEngine from TreeModel SEO靠我import TreeModel,TreeNode import sysif __name__ == __main__:# 创建树形结构rootItem = TreeNode("rooSEO靠我t")childItem1 = TreeNode("child1", rootItem)childItem2 = TreeNode("child2", rootItem)childItem3 = TrSEO靠我eeNode("child3", rootItem)subChildItem1 = TreeNode("sub_child1", childItem1)subChildItem2 = TreeNodeSEO靠我("sub_child2", childItem1)rootItem.appendChild(childItem1)rootItem.appendChild(childItem2)rootItem.aSEO靠我ppendChild(childItem3)childItem1.appendChild(subChildItem1)childItem1.appendChild(subChildItem2)# 创建SEO靠我树形数据模型treeModel = TreeModel(rootItem)# 启动app = QGuiApplication([])engine = QQmlApplicationEngine()enSEO靠我gine.rootContext().setContextProperty(treeModel, treeModel)engine.load(QUrl.fromLocalFile(main.qml))SEO靠我engine.quit.connect(app.quit)sys.exit(app.exec())

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

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

运行命令:

python main.py

未实现

双击编辑节点

参考

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

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

“SEO靠我”的新闻页面文章、图片、音频、视频等稿件均为自媒体人、第三方机构发布或转载。如稿件涉及版权等问题,请与 我们联系删除或处理,客服邮箱:html5sh@163.com,稿件内容仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同 其观点或证实其内容的真实性。

网站备案号:浙ICP备17034767号-2