🐟🐟🐟 实现TreeWidget中的复选框及多级联动
实现方法
- 添加复选框
QtDesigner绘制出的TreeWidget控件是不具有复选框的功能,需要通过setCheckState(index, state)来对TreeWidget中的Item进行复选框的添加,index指的是列的序号,state则为添加时复选框的三种状态(Qt.Checked,Qt.Unchecked,Qt.PartiallyChecked)。例子中通过setTreeCheckBox()来实现复选框的添加。
# 给树添加复选框def setTreeCheckBox(self):root_node = self.treeWidget.topLevelItem(0)root_node.setCheckState(0, Qt.Unchecked)for i in range(root_node.childCount()):parent_node = root_node.child(i)parent_node.setCheckState(0, Qt.Unchecked)if parent_node.childCount() > 0:for j in range(parent_node.childCount()):child_node = parent_node.child(j)child_node.setCheckState(0, Qt.Unchecked)self.treeWidget.expandAll() # 展开树
- 实现复选框多级联动
复选框的多级联动实现主要是通过TreeWidget中自带的信号(itemChanged (QTreeWidgetItem * item , int column ))来实现。通过接收信号传输的Item对Item进行从上往下的遍历用来联动子节点的状态,以及通过自下而上的遍历来联动父节点的状态。由于在进行节点联动时,所有因为联动而改变状态的节点也会触发信号传输,所以在槽函数中不需要做递归操作。
# 设置节点联动事件def onItemChange(self, item):# 联动子节点状态if item.checkState(0) != Qt.PartiallyChecked:state = item.checkState(0) # 存储节点状态防止联动时导致状态进行改变for i in range(item.childCount()):item.child(i).setCheckState(0, state)# 联动父节点状态if item.parent() is not None:check = 0uncheck = 0for j in range(item.parent().childCount()):state = item.parent().child(j).checkState(0)if state == Qt.Unchecked:uncheck += 1else:check += 1if check > 0 and uncheck == 0:item.parent().setCheckState(0, Qt.Checked) # 设置父节点为全选elif check == 0 and uncheck > 0:item.parent().setCheckState(0, Qt.Unchecked) # 设置父节点为未选中else:item.parent().setCheckState(0, Qt.PartiallyChecked) # 设置父节点为部分选中
效果展示

UI部分
from PySide2.QtCore import *from PySide2.QtGui import *from PySide2.QtWidgets import *class Ui_Dialog(object):def setupUi(self, Dialog):if not Dialog.objectName():Dialog.setObjectName(u"Dialog")Dialog.resize(400, 300)self.horizontalLayout = QHBoxLayout(Dialog)self.horizontalLayout.setObjectName(u"horizontalLayout")self.treeWidget = QTreeWidget(Dialog)__qtreewidgetitem = QTreeWidgetItem(self.treeWidget)QTreeWidgetItem(__qtreewidgetitem)__qtreewidgetitem1 = QTreeWidgetItem(__qtreewidgetitem)QTreeWidgetItem(__qtreewidgetitem1)QTreeWidgetItem(__qtreewidgetitem1)__qtreewidgetitem2 = QTreeWidgetItem(__qtreewidgetitem)QTreeWidgetItem(__qtreewidgetitem2)QTreeWidgetItem(__qtreewidgetitem2)self.treeWidget.setObjectName(u"treeWidget")self.horizontalLayout.addWidget(self.treeWidget)self.retranslateUi(Dialog)QMetaObject.connectSlotsByName(Dialog)# setupUidef retranslateUi(self, Dialog):Dialog.setWindowTitle(QCoreApplication.translate("Dialog", u"Dialog", None))___qtreewidgetitem = self.treeWidget.headerItem()___qtreewidgetitem.setText(0, QCoreApplication.translate("Dialog", u"Test", None));__sortingEnabled = self.treeWidget.isSortingEnabled()self.treeWidget.setSortingEnabled(False)___qtreewidgetitem1 = self.treeWidget.topLevelItem(0)___qtreewidgetitem1.setText(0, QCoreApplication.translate("Dialog", u"\u5168\u90e8\u9879\u76ee", None));___qtreewidgetitem2 = ___qtreewidgetitem1.child(0)___qtreewidgetitem2.setText(0, QCoreApplication.translate("Dialog", u"\u9879\u76ee1", None));___qtreewidgetitem3 = ___qtreewidgetitem1.child(1)___qtreewidgetitem3.setText(0, QCoreApplication.translate("Dialog", u"\u9879\u76ee2", None));___qtreewidgetitem4 = ___qtreewidgetitem3.child(0)___qtreewidgetitem4.setText(0, QCoreApplication.translate("Dialog", u"hello", None));___qtreewidgetitem5 = ___qtreewidgetitem3.child(1)___qtreewidgetitem5.setText(0, QCoreApplication.translate("Dialog", u"world", None));___qtreewidgetitem6 = ___qtreewidgetitem1.child(2)___qtreewidgetitem6.setText(0, QCoreApplication.translate("Dialog", u"\u9879\u76ee3", None));___qtreewidgetitem7 = ___qtreewidgetitem6.child(0)___qtreewidgetitem7.setText(0, QCoreApplication.translate("Dialog", u"bye", None));___qtreewidgetitem8 = ___qtreewidgetitem6.child(1)___qtreewidgetitem8.setText(0, QCoreApplication.translate("Dialog", u"good", None));self.treeWidget.setSortingEnabled(__sortingEnabled)
逻辑代码
from PySide2.QtCore import *from PySide2.QtGui import *from PySide2.QtWidgets import *from Test import Ui_Dialogclass TestDialog(QDialog, Ui_Dialog):def __init__(self):super().__init__()self.setupUi(self)self.callback()def setupUi(self, Dialog):super().setupUi(Dialog)self.setTreeCheckBox()Dialog.setWindowFlags(Qt.FramelessWindowHint)# 回调函数def callback(self):self.treeWidget.itemChanged.connect(self.onItemChange)# 给树添加复选框def setTreeCheckBox(self):root_node = self.treeWidget.topLevelItem(0)root_node.setCheckState(0, Qt.Unchecked)for i in range(root_node.childCount()):parent_node = root_node.child(i)parent_node.setCheckState(0, Qt.Unchecked)if parent_node.childCount() > 0:for j in range(parent_node.childCount()):child_node = parent_node.child(j)child_node.setCheckState(0, Qt.Unchecked)self.treeWidget.expandAll() # 展开树# 设置节点联动事件def onItemChange(self, item):if item.checkState(0) != Qt.PartiallyChecked:state = item.checkState(0)for i in range(item.childCount()):item.child(i).setCheckState(0, state)if item.parent() is not None:check = 0uncheck = 0for j in range(item.parent().childCount()):state = item.parent().child(j).checkState(0)if state == Qt.Unchecked:uncheck += 1else:check += 1if check > 0 and uncheck == 0:item.parent().setCheckState(0, Qt.Checked)elif check == 0 and uncheck > 0:item.parent().setCheckState(0, Qt.Unchecked)else:item.parent().setCheckState(0, Qt.PartiallyChecked)if __name__ == '__main__':import sysapp = QApplication(sys.argv)window = TestDialog()window.show()sys.exit(app.exec_())
