pyside2系列之QTreeWidget

本文介绍了如何使用Qt的QTreeWidget类展示文件夹结构,并在切换节点前进行条件判断。通过QTreeWidgetItem添加和管理节点,利用itemPressed、itemClicked和currentItemChanged等信号实现交互。示例代码展示了遍历目录并将文件夹结构加载到QTreeWidget中,同时在切换到特定节点前检查其他节点的修改状态,确保数据不丢失。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • QTreeWidget 是管理类似目录之类,树结构的类。
  • QTreeWidget 每个节点可有多列,节点层次可以嵌套。
  • QTreeWidget 每个节点是 QTreeWidgetItem。
  • QTreeWidget 每个节点可设置类型,文本,字体,图标,还有自定义数据,是否展开,是否selected,CheckState,flags属性(设置节点是否可选、是否可编辑、是否有CheckBox)。
    • 在构造函数传递一个类型值,QTreeWidgetItem.type()函数可以返回这个类型值。
  • QTreeWidget 分为 顶层节点(TopLevelItem)和非顶层节点。
    • 通过 addTopLevelItem 添加顶层节点。
    • 顶层节点和非顶层节点通过 addChild 添加子节点 或者 子节点指定父类
    • removeChild() 函数用于移除一个节点及其所有子节点。有很多关于child的函数
    • 删除顶层节点,使用 QTreeWidget.takeTopLevelItem(index) 函数。
    • 遍历节点 或者 要访问所有顶层节点,需要  topLevelItemCount()  和 topLevelItem(index)。
  •  QTreeWidget 信号
    • 事件如图
    • itemPressed 是鼠标按下未松开。
    • itemClicked 是鼠标按下并弹起。

以下是个例子,该例子遍历文件夹展示到QTreeWidget中 :

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@author: wind
@contact: 367059791@qq.com
@time: 2022/2/24 13:46
@file: demo_qtreewidget.py
@desc: 
"""
import sys
import os
from os import path as osp
from enum import Enum, unique

from PySide2.QtWidgets import (
    QTreeWidget, QApplication, QWidget, QPushButton, QVBoxLayout,
    QFileDialog, QTreeWidgetItem, QStyle
)
from PySide2.QtCore import Qt


@unique
class NodeType(Enum):
    """节点类型,文件还是文件夹"""
    NodeDir = 0
    NodeFile = 1


class DemoTreeWidget(QWidget):
    def __init__(self, parent=None):
        super(DemoTreeWidget, self).__init__(parent)
        self.setFixedSize(600, 400)
        self.setWindowTitle("DemoTreeWidget")

        self.project_tree = QTreeWidget(self)
        self.btn_load = QPushButton("加载工程", self)

        self.init_layout()
        self.init_ctl()

    def init_ctl(self):
        self.btn_load.clicked.connect(self.load_project)
        self.project_tree.header().setVisible(False)     # 隐藏表头

    def init_layout(self):
        v_layout = QVBoxLayout()
        v_layout.addWidget(self.project_tree)
        v_layout.addWidget(self.btn_load, alignment=Qt.AlignRight)
        self.setLayout(v_layout)

    def load_project(self):
        directory = QFileDialog.getExistingDirectory(self, "选择工程目录", ".",
                                                     QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks)
        if not directory:
            return

        top_item = self.create_top_item(directory)   # 创建topitem
        self.list_dir(top_item, directory)      # 递归遍历

    def list_dir(self, parent, directory):
        for obj in os.listdir(directory):
            tmp_path = osp.join(directory, obj)
            if osp.isdir(tmp_path):
                dir_item = self._generate_item(parent, obj, tmp_path, NodeType.NodeDir.value)
                self.list_dir(dir_item, tmp_path)
            else:
                self._generate_item(parent, obj, tmp_path, NodeType.NodeFile.value)

    def _generate_item(self, parent, name, path, node_type):
        item = QTreeWidgetItem(parent, node_type)
        item.setText(0, name)
        item.setToolTip(0, path)
        item.setData(0, Qt.UserRole, path)
        item.setIcon(0, self.style().standardIcon(QStyle.SP_DirIcon if node_type == NodeType.NodeDir.value else QStyle.SP_FileIcon))
        return item

    def create_top_item(self, project_path):
        if not project_path:
            return

        # root
        project_name = osp.basename(project_path)
        top_item = QTreeWidgetItem(self.project_tree, NodeType.NodeDir.value)
        top_item.setText(0, project_name)
        top_item.setToolTip(0, project_path)
        top_item.setData(0, Qt.UserRole, project_path)
        top_item.setIcon(0, self.style().standardIcon(QStyle.SP_DirIcon))
        self.project_tree.addTopLevelItem(top_item)
        return top_item


if __name__ == "__main__":
    app = QApplication(sys.argv)
    wnd = DemoTreeWidget()
    wnd.show()
    sys.exit(app.exec_())

 想在切换到某个节点之前,判断一些条件,不满足就不切换,该如何处理呢?比如下图,想在切换到“第2场”前,判断第1场是否被修改过,若修改过就不切换,必须先保存,以免丢失修改内容。笔者尝试了 itemPressed和itemClicked没能成功,最后采用了 currentItemChanged 和 mousePressEvent 最后解决。有疑问可咨询。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值