网上大部分都是treewidget按钮的选中互斥,直接setselectionmode,自己搞了个节点前面的复选框,就是打对勾的那个小框框,只能选一个。
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qt
'''常见信号'''
# currentItemChanged: 当前条目发生更改时,发射该信号;
# itemActivated: 当条目被激活时,发射该信号;
# itemChanged: 当条目数据发生改变时,发射该信号;
# itemClicked: 点击条目时,发射该信号;
# itemCollapsed: 条目折叠时,发射该信号;
# itemDoubleClicked: 双击一个条目时,发射该信号;
# itemEntered: 当鼠标进入一个条目时,发射该信号;
# itemExpanded: 条目展开时,发射该信号;
# itemPressed: 当按下表格中的条目时,发射该信号;
# itemSelectionChanged: 选择发生更改时,将发射该信号。
class myQTreeWidgetItem(QTreeWidgetItem): # 重写child的type
def type(self) -> int:
return 10
Type = 10
class TreeWidgetDemo(QMainWindow):
def __init__(self, parent=None,radio=True):
self.radio=radio
super(TreeWidgetDemo, self).__init__(parent)
self.setWindowTitle('TreeWidget 例子')
self.resize(500,500)
self.attrdict={'人':['行走','静止'],'车':['1','2','3'],'障碍物':['a','b']}
self.tree = QTreeWidget(self)
self.tree.resize(200,200)
self.tree.move(0,200)
# 设置列数
self.tree.setColumnCount(2)
# 设置树形控件头部的标题
self.tree.setHeaderLabels(['attr_level1', 'attr_level2'])
# 构造treewidget
for attr1,attr2s in self.attrdict.items():
father=QTreeWidgetItem(self.tree)
# father.setFlags(father.flags()|Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable | Qt.ItemIsAutoTristate)
father.setText(0,attr1)
father.setCheckState(0, Qt.Unchecked)
for attr2 in attr2s:
child=myQTreeWidgetItem(father) # 重写的treewidget,child.type=10
# child.setFlags(child.flags()|Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable | Qt.ItemIsAutoTristate)
child.setText(1,attr2)
child.setCheckState(1, Qt.Unchecked)
self.tree.itemChanged.connect(self.itemcheckchanged) # itemchanged ---- checkstate 的信号self.onClicked
# 节点全部展开
self.tree.expandAll()
def itemcheckchanged(self,item):
if item.type()==10 and self.radio: # radio控制单选与否,=true时单选,=false时可多选
if item.checkState(1)==Qt.Checked:
text=item.text(1)
self.updateself(item,text)
elif not self.radio:
self.updateparent(item)
elif item.type()==0: # 原treewidget中father.type=10
self.updatechild()
def updatechild(self): # 父不选时,子全不选
items = self.tree.findItems('', Qt.MatchContains | Qt.MatchRecursive, 0)
for item in items:
if not item.parent() and item.checkState(0)==Qt.Unchecked:
for i in range(item.childCount()):
item.child(i).setCheckState(1,Qt.Unchecked)
def updateself(self,iteml,text=None): # 子选其他子不选
parent = iteml.parent()
if parent and self.radio:
itemCount = parent.childCount()
for i in range(itemCount):
item=parent.child(i)
if item!=iteml:
if item.checkState(1) == Qt.Checked:
item.setCheckState(1,Qt.Unchecked)
for i in range(itemCount):
item=parent.child(i)
if item.text(1)==text:
item.setCheckState(1,Qt.Checked)
self.updateparent(iteml)
def updateparent(self,iteml): # 父是否选中
parent=iteml.parent()
if parent is None:
self.updatechild()
return
checkcount=0
itemCount=parent.childCount()
for i in range(itemCount):
item=parent.child(i)
# print(item.checkState(0))
if item.checkState(1)==Qt.Checked:
checkcount+=1
if checkcount<=0:
parent.setCheckState(0,Qt.Unchecked)
else:
parent.setCheckState(0,Qt.Checked)
self.updatechild()
# 节点前面的复选框,就是打对勾的那个小框框,只能选一个
if __name__ == '__main__':
app = QApplication(sys.argv)
tree = TreeWidgetDemo()
tree.show()
sys.exit(app.exec_())