PyQt常用控件使用介绍:QTreeWidget树结构

文章目录

一、QTreeWidget介绍与常用函数

QTreeWidget是 PyQt 中用于显示树形结构数据的控件,继承自 QTreeView。它通过节点和子节点的层级关系展示数据,常用于文件浏览器、目录结构或分类管理界面。常用函数如下

项初始化

函数 含义
clear() 清空所有节点(包括子节点),释放内存
setColumnCount(int columns) 设置树的列数(默认1列)
setHeaderLabels(QStringList labels) 设置列标题
setColumnWidth(0, 200) 设置列宽(第一列宽度200)
header().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents) 列宽自适应
QTreeWidgetItem(root_tree) 节点加载root_tree上
setText(0, "根节点") 设置内容
setIcon(0, QIcon("")) 设置图片
setCheckState(0, QtCore.Qt.Unchecked) 设置选中状态(勾选框)
addTopLevelItem(QTreeWidgetItem *item) 在顶层添加一个项
addTopLevelItems(QList<QTreeWidgetItem *> items) 批量添加顶层项
insertTopLevelItem(int index, QTreeWidgetItem *item) 在指定位置插入顶层项
takeTopLevelItem(int index) 移除但不删除指定位置的顶层项
addChild(QTreeWidgetItem *parent, QTreeWidgetItem *child) 为父项添加子项
insertChild(int index, QTreeWidgetItem *parent, QTreeWidgetItem *child) 在父项的指定位置插入子项
setHeaderItem(QTreeWidgetItem *item) 自定义标题项(可设置字体/颜色等)
setCurrentItem(QTreeWidgetItem *item) 设置当前选中项

项的相关信息获取

函数 含义
currentItem() 获取当前选中的项(控件对象)
columnCount() 获取当前列数(控件对象)
invisibleRootItem().childCount() 获取根节点的子节点数(控件对象)
invisibleRootItem().child(i) 获取根节点的某个子节点(控件对象)
childCount() 获取当前节点的子节点数(invisibleRootItem()返回的对象)
child(i) 获取当前节点的某个子节点
checkState(0) 获取选中状态(参数表示哪列)
text(0) 获取某列内容(参数表示哪列)
parent().text(column) 获取父节点内容(参数表示哪列)
selectedItems() 获取所有选中的项列表
indexFromItem(QTreeWidgetItem *item) 获取项的模型索引
findItems(QString text, Qt::MatchFlags flags, int column) 查找匹配项
topLevelItem(int index) 获取指定索引的顶层项
topLevelItemCount() 获取顶层项数量
itemAbove(QTreeWidgetItem *item) 获取上一个同级项
itemBelow(QTreeWidgetItem *item) 获取下一个同级项

其他相关函数

函数 含义
expandItem(const QTreeWidgetItem *item) 展开指定节点(显示子节点)
collapseItem(const QTreeWidgetItem *item) 折叠指定节点(隐藏子节点)
expandAll() 全部展开
collapseAll() 全部收起
scrollToItem(QTreeWidgetItem *item) 滚动到指定项
setIndentation(int indent) 设置缩进像素值
setRootIsDecorated(bool show) 显示/隐藏根项展开标记
sortItems(int column, Qt::SortOrder order) 按指定列排序
setSortingEnabled(bool enable) 启用/禁用排序功能
setItemWidget(QTreeWidgetItem *item, int column, QWidget *widget) 为项设置自定义控件
visualItemRect(QTreeWidgetItem *item) 获取项在视图中的显示区域

1.1 树结构的初始化

python 复制代码
# 创建QTreeWidget对象
self.tree_widget = QTreeWidget()

# 设置列数、列标题、列宽
self.tree_widget.setColumnCount(2)
self.tree_widget.setHeaderLabels(["名称", "类型"])
self.tree_widget.setColumnWidth(0, 200)
self.tree_widget.setColumnWidth(1, 150)
# self.tree_widget.header().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)  # 列宽自适应

# 初始化表格
root_item1 = QtWidgets.QTreeWidgetItem(self.tree_widget)
root_item1.setText(0, "root1")
root_item1.setText(1, "dir1")
# root_item1.setCheckState(0, QtCore.Qt.Unchecked)  # 设置勾选状态(不勾选)  可省略

# 同上
root_item2 = QtWidgets.QTreeWidgetItem(["root2", "dir2"])
self.tree_widget.addTopLevelItem(root_item2)

# 第二列增加一个按钮
root_item3 = QtWidgets.QTreeWidgetItem(["root3", "dir3"])
btn = QtWidgets.QPushButton("Button")
self.tree_widget.addTopLevelItem(root_item3)
self.tree_widget.setItemWidget(root_item3, 1, btn)  # 如果为子节点,则root_item3改为子节点对象

# 子节点
root_item4 = QtWidgets.QTreeWidgetItem(root_item3, ["root4", "dir4"])

self.tree_widget.expandAll()      # 所有节点展开
self.tree_widget.collapseAll()    # 所有节点收起

1.2 递归读取完整树结构

python 复制代码
# 创建QTreeWidget实例
tree_widget = QTreeWidget()    # 初始化...略
# 获取信息
root = self.tree_widget.invisibleRootItem()
for iin range(root.childCount()):
    # 获取当前节点信息、选中状态
    item = root.child(i)
    print(item.text(0), item.text(1), item.checkState(0))
    # 获取子节点信息
    for j in range(item.childCount()):
        child_item = item.child(j)
        print(child_item.text(0), child_item.text(1), child_item.checkState(0))

二、QTreeWidget事件绑定

函数 含义
itemClicked.connect() 项被点击
itemDoubleClicked.connect() 项被双击
itemChanged.connect() 勾选状态变化事件(勾选框)
setContextMenuPolicy(QtCore.Qt.CustomContextMenu) customContextMenuRequested.connect(self.right_clicked_tree) 右击事件
valueChanged.connect() 滚轮滚动
itemSelectionChanged.connect() 选中项改变
itemSelectionChanged.connect() 项选择变化
itemExpanded.connect() 项展开
itemCollapsed.connect() 项折叠
itemChanged.connect() 项内容编辑

2.1 单/双击事件

python 复制代码
# 单击事件
self.tree_widget.itemClicked.connect(self.OnClickedItem)
# 双击
# self.tree_widget.itemDoubleClicked.connect(self.clicked_item)

def OnClickedItem(self, item, column):  # item: 点击项   column:列
    if item:
        # 当前节点信息
        item_text = item.text(column)   # item.text(0)
        # 获取父节点信息
        if item.parent():
            parent_text = item.parent().text(column)
        # 获取子节点信息
        for child_index in range(item.childCount()):
            child_text = item.child(child_index).text(column)

2.2 勾选状态事件(勾选框)

python 复制代码
self.tree_widget.itemChanged.connect(self.OnItemChanged)

def OnItemChanged(self, item, column):  # item: 点击项   column:列
    if item.checkState(0) == Qt.Checked:
        print(f"项目 {item.text(0)} 被选中")
    else:
        print(f"项目 {item.text(0)} 取消选中")

多层级勾选框:对于多层级勾选事件,可能有这么个需求,勾选该节点时,该节点的子节点都勾选上,当前层的如果都勾选上了,则该节点的父节点也自动勾选上,实现代码如下

python 复制代码
self.tree_widget.itemChanged.connect(self.OnItemChanged)

def OnItemChanged(self, item, column):
    try:
        self.tree_widget.itemChanged.disconnect(self.on_item_change)
    except Exception as e:
        pass
    # 处理子节点
    self.DeepOnItemChangeChild(item)
    # 处理父节点
    self.DeepOnItemChangeParent(item.parent())
    self.tree_widget.itemChanged.connect(self.on_item_change)

# 遍历处理子节点
def DeepOnItemChangeChild(self, item):
    check_flag = QtCore.Qt.Checked if item.checkState(0) == QtCore.Qt.Checked else QtCore.Qt.Unchecked
    for i in range(item.childCount()):
        child = item.child(i)
        child.setCheckState(0, check_flag)
        self.DeepOnItemChangeChild(child)

# 遍历处理父节点
def DeepOnItemChangeParent(self, item):
    if item:
        item.setCheckState(0, QtCore.Qt.Unchecked)
        for i in range(item.childCount()):
            if item.child(i).checkState(0) != QtCore.Qt.Checked:
                break
        else:
            item.setCheckState(0, QtCore.Qt.Checked)
        self.DeepOnItemChangeParent(item.parent())

2.3 右击菜单栏

如实现右击弹出菜单栏,将当前选选项移除

python 复制代码
# 右击绑定事件
self.tree_widget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.tree_widget.customContextMenuRequested.connect(self.RightClickedTree)

def RightClickedTree(self, pos):
    item = self.tree_widget.itemAt(pos)
    if item:
        menu = QMenu(self.tree_widget)
        remove_item = QAction("remove", self.tree_widget)
        remove_item.triggered.connect(lambda: self.RemoveItem(item))   # 移除事件绑定
        menu.addAction(remove_item)
        menu.exec_(QtGui.QCursor.pos())

# 移除当前项
def RemoveItem(self, item):
    if item.parent():
        item.parent().removeChild(item)
    else:
        index = self.tree_widget.indexOfTopLevelItem(item)
        self.tree_widget.takeTopLevelItem(index)

一般来说,直接使用Menu,对选项右击也会出发事件,这是需要对menu进行部分函数封装改写,忽略右击对菜单栏选项操作

python 复制代码
class MyMenu(QtWidgets.QMenu):
    # 忽略右击选项
    def mousePressEvent(self, event):
        if event.button() == QtCore.Qt.LeftButton:
            super().mousePressEvent(event)
        else:
            event.ignore()

2.4 两QTreeWidget滑轮同步滑动

python 复制代码
# 创建并初始化
self.tree1 = QtWidgets.QTreeWidget()
self.tree2 = QtWidgets.QTreeWidget()
for i in range(100):
    QtWidgets.QTreeWidgetItem(self.tree1).setText(0, str(i))
    QtWidgets.QTreeWidgetItem(self.tree2).setText(0, str(i))

# 获取水平滚动条
scoll1 = self.tree1.verticalScrollBar()
scoll2 = self.tree2.verticalScrollBar()
# 同步滚动
scoll1.valueChanged.connect(lambda val: scoll2.setValue(val))
scoll2.valueChanged.connect(lambda val: scoll1.setValue(val))

三、封装改写QTreeWidget

对于开发,很多功能可能会重复使用,这是可以继承改写原有的类,方便后期开发

python 复制代码
class MyQTreeWidgetItem(QTreeWidget):
    '''
    title_list: 列标题栏
    width_list: 列宽
    select_flag: 是否启动勾选框相应事件绑定
    '''
    def __init__(self, title_list, width_list=[], select_flag=False):
        super().__init__()
        self.setColumnCount(len(title_list))
        self.setHeaderLabels(title_list)
        for width in width_list:
            self.setColumnWidth(width, width)

        self.itemChanged.connect(self.onItemChange) if select_flag else None

    def onItemChange(self, item, column):
        try:
            self.itemChanged.disconnect(self.onItemChange)
        except Exception as e:
            pass
        # 处理子节点
        self.deepOnItemChangeChild(item)
        # 处理父节点
        self.deepOnItemChangedParent(item.parent())
        self.itemChanged.connect(self.onItemChange)

    # 递归处理子节点
    def deepOnItemChangeChild(self, item):
        check_flag = QtCore.Qt.Checked if item.checkState(0) == QtCore.Qt.Checked else QtCore.Qt.Unchecked
        for i in range(item.childCount()):
            child = item.child(i)
            child.setCheckState(0, check_flag)
            self.deepOnItemChangeChild(child)

    # 递归处理父节点
    def deepOnItemChangedParent(self, item):
        if item:
            item.setCheckState(0, QtCore.Qt.Unchecked)
            for i in range(item.childCount()):
                if item.child(i).checkState(0) == QtCore.Qt.Checked:
                    item.setCheckState(0, QtCore.Qt.Checked)
                    break
            self.deepOnItemChangedParent(item.parent())

    # 获取选中的内容(勾选框)
    def getSelectList(self):
        select_list = []
        root = self.invisibleRootItem()
        for i in range(root.childCount()):
            if root.child(i).checkState(0) == QtCore.Qt.Checked:
                select_list.append(root.child(i).text(0))
        return select_list

    # 添加节点
    """
    root: 创建节点属于哪个节点的子节点
    message_list: 展示的内容
    select_flag: 是否启动勾选框
    """
    @staticmethod
    def addItem(root, message_list, select_flag=False):
        child = QTreeWidgetItem(root)
        for i in range(len(message_list)):
            child.setText(i, message_list[i])
        child.setCheckState(0, QtCore.Qt.Unchecked) if select_flag else None
        return child
相关推荐
棒棒的皮皮1 小时前
【OpenCV】Python图像处理之IDE(PyCharm)安装
ide·python·opencv
帮帮志1 小时前
安装了多个不同版本的pycharm,新安装的pycharm打不开
ide·python·pycharm
少废话h4 小时前
解决Flink中ApacheCommonsCLI版本冲突
开发语言·python·pycharm
serve the people4 小时前
TensorFlow 图执行(tf.function)的 “非严格执行(Non-strict Execution)” 特性
人工智能·python·tensorflow
天命码喽c4 小时前
GraphRAG-2.7.0整合Milvus-2.5.1
开发语言·python·milvus·graphrag
吴佳浩7 小时前
LangChain 深入
人工智能·python·langchain
网安-轩逸9 小时前
回归测试原则:确保软件质量的基石
自动化测试·软件测试·python
Mr_Xuhhh9 小时前
YAML相关
开发语言·python
咖啡の猫9 小时前
Python中的变量与数据类型
开发语言·python