news 2026/6/10 20:15:20

PyQt(12)TreeWidget与TreeView对比

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PyQt(12)TreeWidget与TreeView对比

1.TreeWidget实现树形列表 勾选与右键菜单

import sys from PyQt5.QtWidgets import ( QApplication, QMainWindow, QTreeWidget, QTreeWidgetItem, QMenu, QAction, QMessageBox ) from PyQt5.QtCore import Qt class TreeWidgetDemo(QMainWindow): def __init__(self): super().__init__() self._is_updating = False # 防递归死循环标志 self.init_ui() def init_ui(self): self.setWindowTitle("QTreeWidget 勾选联动示例") self.setGeometry(100, 100, 600, 400) # 1. 创建 TreeWidget self.tree_widget = QTreeWidget(self) self.setCentralWidget(self.tree_widget) self.tree_widget.setColumnCount(1) self.tree_widget.setHeaderLabel("文件目录") # 2. 启用节点勾选功能(支持半选状态) self.tree_widget.setSelectionMode(QTreeWidget.ExtendedSelection) self.tree_widget.setItemsExpandable(True) self.tree_widget.setExpandsOnDoubleClick(True) # 3. 构建树形节点(带勾选框,支持半选) self._create_tree_items() # 4. 绑定右键菜单和勾选变化事件 self.tree_widget.setContextMenuPolicy(Qt.CustomContextMenu) self.tree_widget.customContextMenuRequested.connect(self.show_right_menu) self.tree_widget.itemChanged.connect(self.on_item_check_changed) def _create_tree_items(self): """创建树形节点,启用勾选框(支持半选)""" # 根节点1:文档 root1 = QTreeWidgetItem(self.tree_widget, ["文档"]) # 启用勾选+半选功能 root1.setFlags(root1.flags() | Qt.ItemIsUserCheckable) root1.setCheckState(0, Qt.Unchecked) # 子节点1-1/1-2 child1_1 = QTreeWidgetItem(root1, ["简历.docx"]) child1_1.setFlags(child1_1.flags() | Qt.ItemIsUserCheckable) child1_1.setCheckState(0, Qt.Unchecked) child1_2 = QTreeWidgetItem(root1, ["报告.pdf"]) child1_2.setFlags(child1_2.flags() | Qt.ItemIsUserCheckable) child1_2.setCheckState(0, Qt.Unchecked) # 根节点2:图片(多级子节点示例) root2 = QTreeWidgetItem(self.tree_widget, ["图片"]) root2.setFlags(root2.flags() | Qt.ItemIsUserCheckable) root2.setCheckState(0, Qt.Unchecked) # 二级节点:风景 child2_1 = QTreeWidgetItem(root2, ["风景"]) child2_1.setFlags(child2_1.flags() | Qt.ItemIsUserCheckable) child2_1.setCheckState(0, Qt.Unchecked) # 三级节点:山川/湖泊 child2_1_1 = QTreeWidgetItem(child2_1, ["山川.jpg"]) child2_1_1.setFlags(child2_1_1.flags() | Qt.ItemIsUserCheckable) child2_1_1.setCheckState(0, Qt.Unchecked) child2_1_2 = QTreeWidgetItem(child2_1, ["湖泊.jpg"]) child2_1_2.setFlags(child2_1_2.flags() | Qt.ItemIsUserCheckable) child2_1_2.setCheckState(0, Qt.Unchecked) self.tree_widget.expandAll() def on_item_check_changed(self, item, column): """勾选状态变化联动处理(核心逻辑)""" if self._is_updating or column != 0: # 避免递归死循环/只处理第0列 return self._is_updating = True # 锁定更新 try: current_state = item.checkState(0) # 1. 父节点变化:同步所有子节点 self._set_child_check_state(item, current_state) # 2. 子节点变化:更新所有父节点(半选/全选/未选) self._update_parent_check_state(item.parent()) finally: self._is_updating = False # 解锁更新 def _set_child_check_state(self, parent_item, check_state): """递归设置父节点下所有子节点的勾选状态""" child_count = parent_item.childCount() for i in range(child_count): child = parent_item.child(i) child.setCheckState(0, check_state) self._set_child_check_state(child, check_state) # 递归处理孙子节点 def _update_parent_check_state(self, parent_item): """递归更新父节点的勾选状态(全选/半选/未选)""" if not parent_item: # 无父节点则终止 return child_count = parent_item.childCount() checked_count = 0 unchecked_count = 0 # 统计子节点勾选状态 for i in range(child_count): child = parent_item.child(i) state = child.checkState(0) if state == Qt.Checked: checked_count += 1 elif state == Qt.Unchecked: unchecked_count += 1 # 更新父节点状态 if checked_count == child_count: parent_item.setCheckState(0, Qt.Checked) # 全选 elif unchecked_count == child_count: parent_item.setCheckState(0, Qt.Unchecked) # 未选 else: parent_item.setCheckState(0, Qt.PartiallyChecked) # 半选 # 递归更新上层父节点 self._update_parent_check_state(parent_item.parent()) # 以下为原有右键菜单等功能(无修改) def show_right_menu(self, pos): current_item = self.tree_widget.itemAt(pos) if not current_item: return menu = QMenu(self.tree_widget) info_action = QAction("查看节点信息", self) info_action.triggered.connect(lambda: self.show_item_info(current_item)) menu.addAction(info_action) toggle_action = QAction("勾选/取消勾选", self) toggle_action.triggered.connect(lambda: self.toggle_item_check(current_item)) menu.addAction(toggle_action) menu.addSeparator() del_action = QAction("删除节点", self) del_action.triggered.connect(lambda: self.delete_item(current_item)) menu.addAction(del_action) menu.exec_(self.tree_widget.mapToGlobal(pos)) def show_item_info(self, item): state_map = { Qt.Unchecked: "未勾选", Qt.PartiallyChecked: "半选", Qt.Checked: "已勾选" } check_state = state_map.get(item.checkState(0), "未知") QMessageBox.information( self, "节点信息", f"名称:{item.text(0)}\n状态:{check_state}" ) def toggle_item_check(self, item): current_state = item.checkState(0) new_state = Qt.Unchecked if current_state == Qt.Checked else Qt.Checked item.setCheckState(0, new_state) def delete_item(self, item): if item.parent() is None: index = self.tree_widget.indexOfTopLevelItem(item) self.tree_widget.takeTopLevelItem(index) else: item.parent().removeChild(item) if __name__ == "__main__": app = QApplication(sys.argv) window = TreeWidgetDemo() window.show() sys.exit(app.exec_())

2.TreeView实现树形列表 勾选与右键菜单

import sys from PyQt5.QtWidgets import ( QApplication, QMainWindow, QTreeView, QMenu, QAction, QMessageBox, QAbstractItemView ) from PyQt5.QtCore import Qt, QModelIndex from PyQt5.QtGui import QStandardItemModel, QStandardItem class TreeViewDemo(QMainWindow): def __init__(self): super().__init__() self._is_updating = False # 防递归死循环标志 self.init_ui() def init_ui(self): self.setWindowTitle("QTreeView 勾选联动示例") self.setGeometry(100, 100, 600, 400) # 1. 创建模型 self.model = QStandardItemModel() self.model.setHorizontalHeaderLabels(["文件目录"]) # 2. 创建 TreeView self.tree_view = QTreeView(self) self.setCentralWidget(self.tree_view) self.tree_view.setModel(self.model) self.tree_view.setSelectionMode(QAbstractItemView.ExtendedSelection) self.tree_view.setExpandsOnDoubleClick(True) self.tree_view.setContextMenuPolicy(Qt.CustomContextMenu) self.tree_view.customContextMenuRequested.connect(self.show_right_menu) # 3. 构建模型节点 self._create_model_items() # 4. 监听模型数据变化 self.model.dataChanged.connect(self.on_model_data_changed) self.tree_view.expandAll() def _create_model_items(self): """创建带勾选联动的节点""" # 根节点1:文档 root1 = QStandardItem("文档") root1.setCheckable(True) root1.setCheckState(Qt.Unchecked) self.model.appendRow(root1) # 子节点1-1/1-2 child1_1 = QStandardItem("简历.docx") child1_1.setCheckable(True) child1_1.setCheckState(Qt.Unchecked) root1.appendRow(child1_1) child1_2 = QStandardItem("报告.pdf") child1_2.setCheckable(True) child1_2.setCheckState(Qt.Unchecked) root1.appendRow(child1_2) # 根节点2:图片(多级示例) root2 = QStandardItem("图片") root2.setCheckable(True) root2.setCheckState(Qt.Unchecked) self.model.appendRow(root2) # 二级节点:风景 child2_1 = QStandardItem("风景") child2_1.setCheckable(True) child2_1.setCheckState(Qt.Unchecked) root2.appendRow(child2_1) # 三级节点:山川/湖泊 child2_1_1 = QStandardItem("山川.jpg") child2_1_1.setCheckable(True) child2_1_1.setCheckState(Qt.Unchecked) child2_1.appendRow(child2_1_1) child2_1_2 = QStandardItem("湖泊.jpg") child2_1_2.setCheckable(True) child2_1_2.setCheckState(Qt.Unchecked) child2_1.appendRow(child2_1_2) def on_model_data_changed(self, top_left: QModelIndex, bottom_right: QModelIndex): """模型数据变化(勾选状态)联动处理""" if self._is_updating or top_left.column() != 0: # 防递归/只处理第0列 return self._is_updating = True try: item = self.model.itemFromIndex(top_left) current_state = item.checkState() # 1. 父节点变化:同步所有子节点 self._set_child_check_state(item, current_state) # 2. 子节点变化:更新所有父节点 self._update_parent_check_state(item.parent()) finally: self._is_updating = False def _set_child_check_state(self, parent_item: QStandardItem, check_state): """递归设置子节点勾选状态""" row_count = parent_item.rowCount() for i in range(row_count): child = parent_item.child(i) if child.isCheckable(): child.setCheckState(check_state) self._set_child_check_state(child, check_state) # 递归处理孙子节点 def _update_parent_check_state(self, parent_item: QStandardItem): """递归更新父节点状态(全选/半选/未选)""" if not parent_item: # 无父节点则终止 return row_count = parent_item.rowCount() checked_count = 0 unchecked_count = 0 # 统计子节点状态 for i in range(row_count): child = parent_item.child(i) if child.isCheckable(): state = child.checkState() if state == Qt.Checked: checked_count += 1 elif state == Qt.Unchecked: unchecked_count += 1 # 更新父节点状态 if checked_count == row_count: parent_item.setCheckState(Qt.Checked) elif unchecked_count == row_count: parent_item.setCheckState(Qt.Unchecked) else: parent_item.setCheckState(Qt.PartiallyChecked) # 递归更新上层父节点 self._update_parent_check_state(parent_item.parent()) # 以下为原有右键菜单等功能(无修改) def show_right_menu(self, pos): index = self.tree_view.indexAt(pos) if not index.isValid(): return menu = QMenu(self.tree_view) info_action = QAction("查看节点信息", self) info_action.triggered.connect(lambda: self.show_item_info(index)) menu.addAction(info_action) toggle_action = QAction("勾选/取消勾选", self) toggle_action.triggered.connect(lambda: self.toggle_item_check(index)) menu.addAction(toggle_action) menu.addSeparator() del_action = QAction("删除节点", self) del_action.triggered.connect(lambda: self.delete_item(index)) menu.addAction(del_action) menu.exec_(self.tree_view.mapToGlobal(pos)) def show_item_info(self, index): item = self.model.itemFromIndex(index) state_map = { Qt.Unchecked: "未勾选", Qt.PartiallyChecked: "半选", Qt.Checked: "已勾选" } check_state = state_map.get(item.checkState(), "未知") QMessageBox.information( self, "节点信息", f"名称:{item.text()}\n状态:{check_state}" ) def toggle_item_check(self, index): item = self.model.itemFromIndex(index) current_state = item.checkState() new_state = Qt.Unchecked if current_state == Qt.Checked else Qt.Checked item.setCheckState(new_state) def delete_item(self, index): if not index.parent().isValid(): self.model.removeRow(index.row()) else: self.model.removeRow(index.row(), index.parent()) if __name__ == "__main__": app = QApplication(sys.argv) window = TreeViewDemo() window.show() sys.exit(app.exec_())

相关文档

PyQt5列表介绍【树控件】-QTreeWidget

https://zhuanlan.zhihu.com/p/17204967078https://zhuanlan.zhihu.com/p/17204967078

PyQt5列表介绍【树控件】-QTreeView

https://zhuanlan.zhihu.com/p/17439921032https://zhuanlan.zhihu.com/p/17439921032

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/9 2:38:46

基于EmotiVoice开发互动游戏语音系统的最佳实践

基于EmotiVoice开发互动游戏语音系统的最佳实践 在现代互动游戏中,玩家早已不再满足于“点击对话框→播放录音”的静态交互模式。他们期待的是能感知情绪、回应情境、甚至带有性格的NPC——一个会因愤怒而颤抖、因悲伤而哽咽、因惊喜而语速加快的“活人”。然而&…

作者头像 李华
网站建设 2026/6/3 2:56:59

TLS网络安全协议巩固知识基础题(5)

1. TLS 1.3中的KeyUpdate消息如何实现密钥更新? 触发方式:任一方主动发送KeyUpdate消息 更新类型: update_not_requested:单向密钥更新 update_requested:请求对方也更新密钥 密钥派生:使用HKDF基于当前traffic secret生成新密钥 2. 解释TLS中的Padding扩展及其安全意义?…

作者头像 李华
网站建设 2026/6/9 3:59:53

基于Beego的轻量级功能权限管理系统设计与实现

基于Beego的轻量级功能权限管理系统设计与实现 基于Beego的轻量级功能权限管理系统:毕业设计源码与论文全解析 在当今数字化时代,权限管理系统已成为Web应用开发中不可或缺的核心组件。无论是企业后台管理系统、内部办公平台,还是SaaS服务&…

作者头像 李华
网站建设 2026/6/10 12:28:53

基于Golang与Vue3的全栈博客系统设计与实现

基于Golang与Vue3的全栈博客系统设计与实现 基于Golang与Vue3的全栈博客系统:毕业设计与学习实践的完美解决方案 在当今数字化时代,博客系统不仅是个人表达和知识分享的平台,更是全栈开发技术学习的绝佳案例。对于计算机科学和软件工程专业…

作者头像 李华
网站建设 2026/6/9 18:30:58

紧急缺人!年薪96万的新兴领域,强烈建议冲一冲

大家好,我是程序员小灰。不得不承认,最近一段时间大环境并不好。在互联网全面进入存量竞争、企业纷纷“降本增效”的大背景下,传统开发岗位的HC正在快速收缩……然而,传统程序员降薪、裁员的同时,AI相关技术岗位却在疯…

作者头像 李华
网站建设 2026/6/9 2:44:25

MOS 管栅极的 “充放电控制 + 可靠性

要分析这个UCC27244D 驱动 MOS 管 Q1电路中 R1、R3、D1、R2 的作用,需要结合 “栅极驱动的充放电、振荡抑制、可靠性” 这几个核心需求来看: 1. R1(100Ω):栅极串联电阻(核心作用是抑制振荡 + 限流) R1 串联在驱动器OUTA与 MOS 管 Q1 的栅极(G)之间,是栅极电阻,作…

作者头像 李华