杰瑞科技汇

Python中QTreeWidget如何高效使用?

QTreeWidget 是 PyQt/PySide 中一个非常常用的控件,它以树形结构来展示分层数据,你可以把它想象成一个文件夹浏览器,其中可以包含顶级项目,每个顶级项目下又可以有子项目,子项目还可以继续嵌套。

Python中QTreeWidget如何高效使用?-图1
(图片来源网络,侵删)

核心概念

要理解 QTreeWidget,首先需要了解三个核心类:

  1. QTreeWidget: 这是整个树形控件的容器,也就是你拖到窗体上的那个“树”本身。
  2. QTreeWidgetItem: 这是树中的“节点”或“项目”,你看到的每一行,无论是顶级节点还是子节点,都是一个 QTreeWidgetItem 对象。
  3. QTreeWidgetItems: 这是一个 QTreeWidgetItem 对象的列表类,当你需要一次性操作多个项目时(获取所有选中的项目),会用到它。

QTreeWidget 是舞台,QTreeWidgetItem 是舞台上的演员。


基本用法

下面我们通过一个完整的例子来学习 QTreeWidget 的基本操作,包括创建、添加、修改和删除节点。

创建和设置

创建一个 QTreeWidget 实例,并设置一些基本属性,如列数。

Python中QTreeWidget如何高效使用?-图2
(图片来源网络,侵删)
import sys
from PyQt5.QtWidgets import QApplication, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
# 1. 创建一个QTreeWidget实例
tree = QTreeWidget()
# 设置列数,这决定了每个节点可以显示多少列数据
tree.setColumnCount(2) tree.setHeaderLabels(["名称", "信息"])
# 2. 创建顶级节点
# 顶级节点是直接添加到QTreeWidget中的
top_item_1 = QTreeWidgetItem(tree)
top_item_1.setText(0, "文件夹 A")
top_item_1.setText(1, "这是文件夹 A 的描述")
top_item_2 = QTreeWidgetItem(tree)
top_item_2.setText(0, "文件夹 B")
top_item_2.setText(1, "这是文件夹 B 的描述")
# 3. 创建子节点
# 子节点是添加到另一个QTreeWidgetItem中的
sub_item_1 = QTreeWidgetItem(top_item_1)
sub_item_1.setText(0, "文件 A-1.txt")
sub_item_1.setText(1, "大小: 1.2 MB")
sub_item_2 = QTreeWidgetItem(top_item_1)
sub_item_2.setText(0, "文件 A-2.txt")
sub_item_2.setText(1, "大小: 850 KB")
sub_item_3 = QTreeWidgetItem(top_item_2)
sub_item_3.setText(0, "图片 B-1.png")
sub_item_3.setText(1, "大小: 4.5 MB")
# 4. (可选)展开所有节点
tree.expandAll()
# 5. (可选)设置窗口大小
tree.resize(400, 300)
# 6. 显示
tree.show()

添加、修改和删除

# 假设 tree 已经存在
# --- 添加节点 ---
# 添加一个新的顶级节点
new_top_item = QTreeWidgetItem(tree)
new_top_item.setText(0, "新文件夹")
# 在 "新文件夹" 下添加一个子节点
new_sub_item = QTreeWidgetItem(new_top_item)
new_sub_item.setText(0, "新文件.txt")
# --- 修改节点 ---
# 假设我们要修改 "文件 A-1.txt" 的信息
# 首先找到这个节点,然后修改它的文本
# 一个简单的方法是遍历(对于复杂的树,需要更高效的查找方法)
for i in range(tree.topLevelItemCount()):
    top_item = tree.topLevelItem(i)
    if top_item.text(0) == "文件夹 A":
        for j in range(top_item.childCount()):
            child_item = top_item.child(j)
            if child_item.text(0) == "文件 A-1.txt":
                child_item.setText(1, "大小: 1.5 MB (已更新)")
                break
        break
# --- 删除节点 ---
# 删除 "新文件夹" 及其所有子节点
# 首先找到这个节点
for i in range(tree.topLevelItemCount()):
    if tree.topLevelItem(i).text(0) == "新文件夹":
        # takeTopLevelItem 会返回被删除的项,并从树中移除
        tree.takeTopLevelItem(i)
        break

高级功能

QTreeWidget 的强大之处在于它支持很多高级功能。

设置图标

可以为每个 QTreeWidgetItem 设置图标,让界面更直观。

from PyQt5.QtGui import QIcon
# ... (前面的代码)
# 创建一个 QIcon 对象 (假设你有一个 'folder.png' 和 'file.png' 文件)
folder_icon = QIcon("folder.png")
file_icon = QIcon("file.png")
# 为顶级节点设置图标
top_item_1.setIcon(0, folder_icon)
top_item_2.setIcon(0, folder_icon)
# 为子节点设置图标
sub_item_1.setIcon(0, file_icon)
sub_item_2.setIcon(0, file_icon)
sub_item_3.setIcon(0, file_icon)

处理用户交互

QTreeWidget 支持多种信号,让你可以对用户的操作做出响应。

  • itemClicked(item, column): 当用户点击一个项目时触发。
  • itemDoubleClicked(item, column): 当用户双击一个项目时触发。
  • itemChanged(item, column): 当用户编辑了项目文本(需要启用编辑)后触发。
  • itemSelectionChanged(): 当选中项发生变化时触发。
from PyQt5.QtCore import Qt
# ... (前面的代码)
# 定义一个槽函数来处理点击事件
def on_item_clicked(item, column):
    # item 是被点击的 QTreeWidgetItem 对象
    # column 是被点击的列索引
    print(f"你点击了: {item.text(0)}, 列: {column}")
    # 你可以在这里根据点击的项执行不同操作
    if item.childCount() > 0:
        print("这是一个父节点。")
    else:
        print("这是一个叶子节点。")
# 连接信号和槽
tree.itemClicked.connect(on_item_clicked)
# 启用编辑功能
# tree.setEditTriggers(QTreeWidget.DoubleClicked | QTreeWidget.EditKeyPressed)

复选框

这是 QTreeWidget 一个非常实用的功能。

Python中QTreeWidget如何高效使用?-图3
(图片来源网络,侵删)
# ... (前面的代码)
# 创建一个带复选框的节点
# 方法1:在创建后设置
checked_item = QTreeWidgetItem(top_item_1)
checked_item.setText(0, "已完成任务")
checked_item.setCheckState(0, Qt.Checked) # Qt.Checked, Qt.Unchecked, Qt.PartiallyChecked
# 方法2:在创建时设置
# checked_item = QTreeWidgetItem(top_item_1, ["待办任务"])
# checked_item.setCheckState(0, Qt.Unchecked)
# 定义一个槽函数来处理复选框状态变化
def on_check_state_changed(item, column):
    # 注意:column 是触发变化的列,对于复选框通常是第0列
    if item.checkState(0) == Qt.Checked:
        print(f"'{item.text(0)}' 已被选中")
    else:
        print(f"'{item.text(0)}' 未被选中")
tree.itemChanged.connect(on_check_state_changed)

自定义控件

QTreeWidget 的每一列不仅可以显示文本,还可以嵌入任何 QWidget 子类,QProgressBar, QComboBox, QPushButton 等。

from PyQt5.QtWidgets import QProgressBar, QComboBox
# ... (前面的代码)
# 为某个节点添加一个进度条
progress_item = QTreeWidgetItem(top_item_2)
progress_item.setText(0, "下载任务")
# 创建一个进度条控件
progress_bar = QProgressBar()
progress_bar.setValue(75) # 设置进度为75%
# 将进度条设置为该节点的第二列的控件
# 参数:列索引,控件,对齐方式
tree.setItemWidget(progress_item, 1, progress_bar)
# 为某个节点添加一个下拉框
combo_item = QTreeWidgetItem(top_item_2)
combo_item.setText(0, "选择优先级")
combo_box = QComboBox()
combo_box.addItems(["低", "中", "高"])
tree.setItemWidget(combo_item, 1, combo_box)

完整示例代码

下面是一个综合了上述所有功能的完整示例。

import sys
from PyQt5.QtWidgets import (QApplication, QTreeWidget, QTreeWidgetItem, 
                             QVBoxLayout, QWidget, QProgressBar, QComboBox)
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import Qt
class TreeWidgetDemo(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()
    def initUI(self):
        self.setWindowTitle('QTreeWidget 综合示例')
        self.setGeometry(300, 300, 500, 400)
        # 主布局
        layout = QVBoxLayout()
        # 创建 QTreeWidget
        self.tree = QTreeWidget()
        self.tree.setColumnCount(3)
        self.tree.setHeaderLabels(['名称', '状态', '操作'])
        # --- 添加节点 ---
        # 顶级节点 1
        top_item_1 = QTreeWidgetItem(self.tree)
        top_item_1.setText(0, "项目文档")
        top_item_1.setIcon(0, QIcon.fromTheme("folder")) # 使用系统图标
        # 子节点 1.1
        doc_item_1 = QTreeWidgetItem(top_item_1)
        doc_item_1.setText(0, "需求说明书.docx")
        doc_item_1.setCheckState(0, Qt.Checked)
        # 子节点 1.2
        doc_item_2 = QTreeWidgetItem(top_item_1)
        doc_item_2.setText(0, "设计图纸.pdf")
        doc_item_2.setCheckState(0, Qt.Unchecked)
        # 顶级节点 2
        top_item_2 = QTreeWidgetItem(self.tree)
        top_item_2.setText(0, "开发任务")
        top_item_2.setIcon(0, QIcon.fromTheme("folder"))
        # 子节点 2.1 (带进度条)
        task_item_1 = QTreeWidgetItem(top_item_2)
        task_item_1.setText(0, "前端开发")
        self.progress_bar = QProgressBar()
        self.progress_bar.setValue(60)
        self.tree.setItemWidget(task_item_1, 1, self.progress_bar)
        # 子节点 2.2 (带下拉框)
        task_item_2 = QTreeWidgetItem(top_item_2)
        task_item_2.setText(0, "后端开发")
        self.priority_combo = QComboBox()
        self.priority_combo.addItems(["低", "中", "高"])
        self.priority_combo.setCurrentIndex(1) # 默认选中"中"
        self.tree.setItemWidget(task_item_2, 1, self.priority_combo)
        # 连接信号
        self.tree.itemClicked.connect(self.on_item_clicked)
        self.tree.itemChanged.connect(self.on_item_changed)
        self.tree.expandAll() # 展开所有节点
        layout.addWidget(self.tree)
        self.setLayout(layout)
    def on_item_clicked(self, item, column):
        print(f"点击了: {item.text(0)} (列: {column})")
        if item.childCount() > 0:
            print(f"  - 这是一个父节点,有 {item.childCount()} 个子节点。")
    def on_item_changed(self, item, column):
        if item.checkState(0) == Qt.Checked:
            print(f"'{item.text(0)}' 被勾选")
        else:
            print(f"'{item.text(0)}' 取消勾选")
if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = TreeWidgetDemo()
    demo.show()
    sys.exit(app.exec_())

QTreeWidget 是 PyQt/PySide 中用于展示层次化数据的强大控件,掌握它的关键在于:

  1. 理解 QTreeWidget (容器) 和 QTreeWidgetItem (节点) 的关系
  2. 熟练掌握基本操作:创建、添加、修改、删除节点,设置列和标题。
  3. 利用高级功能:如图标、复选框、自定义控件,来构建功能丰富和用户友好的界面。
  4. 通过信号和槽机制,响应用户的交互行为。

希望这份详细的指南能帮助你完全掌握 QTreeWidget 的使用!

分享:
扫描分享到社交APP
上一篇
下一篇