PySide6 QTreeWidget如何实现仅复选框单选功能?
解决PySide6 QTreeWidget仅通过复选框实现单选的问题
问题分析
SingleSelection是控制行选择模式的,和复选框的选中状态没有关联;直接在itemChanged回调里修改其他复选框状态会触发信号递归调用,导致逻辑失效。
解决方案
处理itemChanged信号时,先临时阻塞QTreeWidget的信号,修改完所有复选框状态后再恢复信号,避免递归触发。同时要判断当前操作是复选框的状态变化,避免其他item修改(比如文本)触发不必要的逻辑。
完整可运行代码
from PySide6.QtCore import Qt from PySide6.QtWidgets import (QApplication, QTreeWidget, QTreeWidgetItem, QWidget, QVBoxLayout) import sys class CheckboxSingleSelectTree(QTreeWidget): def __init__(self, parent=None): super().__init__(parent) self.setSelectionMode(QTreeWidget.SingleSelection) self.setFocusPolicy(Qt.NoFocus) self.setColumnCount(1) # 添加测试项 for i in range(5): item = QTreeWidgetItem(self, [f"Item {i+1}"]) # 给item添加复选框权限 item.setFlags(item.flags() | Qt.ItemIsUserCheckable) item.setCheckState(0, Qt.Unchecked) self.itemChanged.connect(self.on_item_changed) def on_item_changed(self, item, column): # 只处理复选框所在列的状态变化 if column != 0: return # 仅当当前item被选中时,取消其他项的选中状态 if item.checkState(0) == Qt.Checked: # 阻塞信号,防止修改其他item时再次触发itemChanged self.blockSignals(True) # 遍历所有根节点下的子项 root_item = self.invisibleRootItem() total_items = root_item.childCount() for i in range(total_items): current_item = root_item.child(i) if current_item != item and current_item.checkState(0) == Qt.Checked: current_item.setCheckState(0, Qt.Unchecked) # 恢复信号正常触发 self.blockSignals(False) if __name__ == "__main__": app = QApplication(sys.argv) window = QWidget() layout = QVBoxLayout(window) tree = CheckboxSingleSelectTree() layout.addWidget(tree) window.show() sys.exit(app.exec())
关键细节
- 用
blockSignals(True)临时阻断信号,避免修改其他item复选框时触发递归回调 - 增加列判断,只响应复选框所在列的状态变更
- 遍历根节点下的所有子项,精准取消非当前选中项的复选框状态
内容的提问来源于stack exchange,提问作者user1701820
相关产品推荐
相关产品推荐

