pyside6 控件二:自定义树控件

目录

一、自定义控件(读者可直接Copy)

二、使用案例


一、自定义控件(读者可直接Copy)

import os
import platform

from PySide6 import QtWidgets
from PySide6.QtCore import QObject, Signal, Qt
from PySide6.QtGui import QIcon
from PySide6.QtWidgets import QWidget, QVBoxLayout, QTreeWidget, QApplication, QTreeWidgetItem


class TreeWidgetItem:
    def __init__(self, id: any, parent_id: any, name: str, icon: QIcon = None, extend: object = None):
        """
        菜单数据接口
        :param id: ID
        :param parent_id: 父ID
        :param name: 菜单名称
        :param icon: 图标
        :param extend: 扩展数据
        """
        self.id: any = id
        self.parent_id: any = parent_id
        self.name: str = name
        self.extend: object = extend
        # 实例化
        self.treeWidgetItem = QTreeWidgetItem([self.name])
        # 存储相关数据
        self.treeWidgetItem.setData(0, Qt.UserRole + 1, extend)
        self.treeWidgetItem.setIcon(0, QIcon(':/icons/default.png'))
        if icon is not None:
            self.treeWidgetItem.setIcon(0, icon)


class ElTreeData(QObject):
    """
    Data Model
    """
    items_changed: Signal = Signal(str)
    styleSheet_changed: Signal = Signal(str)

    def __init__(self, items: list[TreeWidgetItem] = None, styleSheet: str = None):
        super(ElTreeData, self).__init__()
        # 定义数据
        self._items: list[TreeWidgetItem]
        self._styleSheet: str
        # 初始化数据
        self.items = items
        self.styleSheet = styleSheet

    @property
    def items(self):
        return self._items

    @items.setter
    def items(self, value):
        self._items = value
        # 数据改变时发出信号
        self.items_changed.emit(self.items)

    @property
    def styleSheet(self):
        return self._styleSheet

    @styleSheet.setter
    def styleSheet(self, value):
        self._styleSheet = value
        # 数据改变时发出信号
        self.styleSheet_changed.emit(self.styleSheet)


"""
初始化CSS文件位置
"""
CSS_PATH = None
if str(platform.system().lower()) == 'windows':
    path = __file__.replace(fr"\{os.path.basename(__file__)}", "").replace("\\\\", "\\")
    CSS_PATH = fr'{path}\el_tree.css'
elif str(platform.system().lower()) == 'linux':
    path = __file__.replace(fr"/{os.path.basename(__file__)}", "").replace("//", "/")
    CSS_PATH = fr'{path}/el_tree.css'
else:
    print(f"未知系统:{platform.system().lower()}")


class ElTreeUi(object):
    """
    User Interface
    """

    def setupUi(self, window):
        with open(CSS_PATH, "r", encoding="UTF-8") as f:
            window.setStyleSheet(f.read())
        window.setWindowTitle("ElTree")
        window.setWindowIcon(QIcon(':/icons/add.png'))
        window.resize(40, 30)

        # 设置整个窗体的透明度
        window.setWindowOpacity(0.90)  # 设置窗体透明度
        # 设置隐藏背景
        window.setAttribute(Qt.WA_TranslucentBackground)
        # 垂直布局
        self.layout = QVBoxLayout()
        # 设置边距为0
        self.layout.setContentsMargins(0, 0, 0, 0)
        window.setLayout(self.layout)
        self._tree = QTreeWidget()

        self._tree.setSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding)
        self.layout.addWidget(self._tree)


class ElTree(QWidget, ElTreeUi):
    """
    Control
    """
    itemClicked: Signal = Signal(object)
    itemDoubleClicked: Signal = Signal(object)

    def __init__(self, treeData: ElTreeData, parent=None):
        super(ElTree, self).__init__(parent=parent)
        self.setupUi(self)
        self.data = treeData
        self.__bind()
        # 将按钮的点击信号绑定到当前类的点击信号
        self._tree.itemClicked.connect(lambda item: self.itemClicked.emit(item.data(0, Qt.UserRole + 1)))
        self._tree.itemDoubleClicked.connect(lambda item: self.itemDoubleClicked.emit(item.data(0, Qt.UserRole + 1)))
        self.__render_items(True)

    def __render_items(self, is_clear: bool):
        if is_clear:
            self._tree.clear()
        self._tree.setColumnCount(1)
        self._tree.setHeaderHidden(True)
        if self.data.items is not None:
            # 转为字典
            mapping: dict[any, TreeWidgetItem] = dict(zip([i.id for i in self.data.items], self.data.items))
            # 树容器
            treeWidgetItems: list[QTreeWidgetItem] = []
            for d in self.data.items:
                # 如果找不到父级项,则是根节点
                parent: TreeWidgetItem = mapping.get(d.parent_id)
                if parent is None:
                    treeWidgetItems.append(d.treeWidgetItem)
                else:
                    parent.treeWidgetItem.addChild(d.treeWidgetItem)

            # 挂载到树上
            self._tree.insertTopLevelItems(0, treeWidgetItems)

    def __bind(self):
        """
        数据绑定到控件属性
        """
        pass

二、使用案例


if __name__ == '__main__':
    """
    Test Demo
    """
    # 引入资源(这一步不能少!)
    from images.resources_rc import *

    app = QApplication([])
    button = ElTree(ElTreeData(items=[
        TreeWidgetItem(1, 0, "User", icon=QIcon(":/icons/add.png"), extend={'id': 1}),
        TreeWidgetItem(2, 1, "Child", icon=QIcon(":/icons/address.png"), extend={'id': 2}),
        TreeWidgetItem(3, 1, "Child", icon=QIcon(":/icons/code_generator.png"), extend={'id': 3}),
        TreeWidgetItem(4, 2, "Child", icon=QIcon(":/icons/linked.png"), extend={'id': 4}),
        TreeWidgetItem(5, 2, "Child", icon=QIcon(":/icons/template.png"), extend={'id': 5}),
        TreeWidgetItem(6, 5, "Child", icon=QIcon(":/icons/template_edit.png"), extend={'id': 6}),
        TreeWidgetItem(7, 5, "Child", extend={'id': 7}),
        TreeWidgetItem(8, 5, "Child", extend={'id': 8}),
        TreeWidgetItem(9, 8, "Child", extend={'id': 9}),
    ]))

    button.itemClicked.connect(lambda extend: print("单击->扩展数据为:", extend))
    button.itemDoubleClicked.connect(lambda extend: print("双击->扩展数据为:", extend))
    button.show()
    app.exec()

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

文子阳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值