🐟🐟🐟 实现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 = 0
uncheck = 0
for j in range(item.parent().childCount()):
state = item.parent().child(j).checkState(0)
if state == Qt.Unchecked:
uncheck += 1
else:
check += 1
if 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)
# setupUi
def 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_Dialog
class 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 = 0
uncheck = 0
for j in range(item.parent().childCount()):
state = item.parent().child(j).checkState(0)
if state == Qt.Unchecked:
uncheck += 1
else:
check += 1
if 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 sys
app = QApplication(sys.argv)
window = TestDialog()
window.show()
sys.exit(app.exec_())