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

核心概念
要理解 QTreeWidget,首先需要了解三个核心类:
QTreeWidget: 这是整个树形控件的容器,也就是你拖到窗体上的那个“树”本身。QTreeWidgetItem: 这是树中的“节点”或“项目”,你看到的每一行,无论是顶级节点还是子节点,都是一个QTreeWidgetItem对象。QTreeWidgetItems: 这是一个QTreeWidgetItem对象的列表类,当你需要一次性操作多个项目时(获取所有选中的项目),会用到它。
QTreeWidget 是舞台,QTreeWidgetItem 是舞台上的演员。
基本用法
下面我们通过一个完整的例子来学习 QTreeWidget 的基本操作,包括创建、添加、修改和删除节点。
创建和设置
创建一个 QTreeWidget 实例,并设置一些基本属性,如列数。

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 一个非常实用的功能。

# ... (前面的代码)
# 创建一个带复选框的节点
# 方法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 中用于展示层次化数据的强大控件,掌握它的关键在于:
- 理解
QTreeWidget(容器) 和QTreeWidgetItem(节点) 的关系。 - 熟练掌握基本操作:创建、添加、修改、删除节点,设置列和标题。
- 利用高级功能:如图标、复选框、自定义控件,来构建功能丰富和用户友好的界面。
- 通过信号和槽机制,响应用户的交互行为。
希望这份详细的指南能帮助你完全掌握 QTreeWidget 的使用!
