BPL*_*BPL 3 python checkbox pyqt qtreeview qstandarditemmodel
考虑这个小片段:
import sys
from PyQt5 import QtWidgets
from PyQt5 import QtWidgets
from PyQt5.QtGui import QStandardItemModel
from PyQt5.QtGui import QStandardItem
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QGridLayout
from PyQt5.QtWidgets import QPushButton
from PyQt5.QtWidgets import QWidget
from PyQt5.QtWidgets import QTreeView
from PyQt5.QtWidgets import QAbstractItemView
packages = {
'tree': {
'parent1': ['child1', 'child2', 'child3'],
'parent2': ['child4', 'child5'],
'parent3': ['child6']
},
'metadata': {
'child1': {'description': 'child1 description', 'enabled': True},
'child2': {'description': 'child2 description', 'enabled': False},
'child3': {'description': 'child3 description', 'enabled': True},
'child4': {'description': 'child4 description', 'enabled': False},
'child5': {'description': 'child5 description', 'enabled': True},
'child6': {'description': 'child6 description', 'enabled': True}
}
}
class McveDialog(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.treeview = QTreeView()
# self.treeview.setHeaderHidden(True)
self.treeview.setUniformRowHeights(True)
# self.treeview.setEditTriggers(QAbstractItemView.NoEditTriggers)
# self.treeview.setSelectionMode(QAbstractItemView.ExtendedSelection)
self.model = QStandardItemModel()
self.model.setHorizontalHeaderLabels(['Package', 'Description'])
metadata = packages['metadata']
tree = packages['tree']
for parent, childs in tree.items():
parent_item = QStandardItem(f'{parent}')
parent_item.setCheckState(True)
parent_item.setCheckable(True)
parent_item.setFlags(parent_item.flags() | Qt.ItemIsAutoTristate)
# parent_item.setFlags(parent_item.flags() | Qt.ItemIsUserTristate)
self.model.appendRow(parent_item)
for child in childs:
description = metadata[child]['description']
checked = metadata[child]['enabled']
child_item = QStandardItem(f'{child}')
check = Qt.Checked if checked else Qt.Unchecked
child_item.setCheckState(check)
child_item.setCheckable(True)
# child_item.setFlags(child_item.flags() |Qt.ItemIsAutoTristate)
parent_item.appendRow(child_item)
self.treeview.setModel(self.model)
self.model.itemChanged.connect(self.on_itemChanged)
layout = QGridLayout()
row = 0
layout.addWidget(self.treeview, row, 0, 1, 3)
row += 1
self.but_ok = QPushButton("OK")
layout.addWidget(self.but_ok, row, 1)
self.but_ok.clicked.connect(self.on_ok)
self.but_cancel = QPushButton("Cancel")
layout.addWidget(self.but_cancel, row, 2)
self.but_cancel.clicked.connect(self.on_cancel)
self.setLayout(layout)
self.setGeometry(300, 200, 460, 350)
def on_itemChanged(self, item):
pass
def on_ok(self):
pass
def on_cancel(self):
self.close()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
dialog = McveDialog()
dialog.setWindowTitle('Mcve dialog')
dialog.show()
sys.exit(app.exec_())
Run Code Online (Sandbox Code Playgroud)
我在这里想要实现的是,当用户选择所有父级的子级时,父级状态将变为选中状态;如果取消选择所有子项,则取消选择父状态;最后,如果选择了一些孩子,那么父母会被部分选中。(反之亦然,因此如果用户取消选择父项,则其所有子项都将被取消选择,如果用户选择父项,则其所有子项都将被选中)。
理论上,这种行为应该通过使用Qt::ItemIsAutoTristate标志来实现,它说:
项目的状态取决于其子项的状态。这可以自动管理 QTreeWidget 中父项的状态(如果所有子项都被选中,则选中,如果所有子项都未选中,则取消选中,或者如果只选中一些子项,则部分选中)。
但是如果你运行上面的代码,你会发现在阅读文档后你会发现行为不是你所期望的。我已经看到有这个bugreport,虽然我不确定它是否与此有关,或者我的代码段是否只是缺少一些东西。
例如,上面的代码片段允许您这样做:
无论如何,问题是,您将如何修复此小部件,使其像任何包安装程序一样运行,您可以在其中选择/取消选择/部分选择所有具有共同父级的子包?
目前,似乎ItemIsAutoTristate仅针对QTreeWidget该类实施。QStandardItem下面的子类为使用QStandardItemModel. 这是一个或多或少忠实的QTreeWidget实现端口。示例代码似乎可以正常工作,但我还没有对其进行测试:
class StandardItem(QStandardItem):
def data(self, role = Qt.UserRole + 1):
if (role == Qt.CheckStateRole and self.hasChildren() and
self.flags() & Qt.ItemIsAutoTristate):
return self._childrenCheckState()
return super().data(role)
def setData(self, value, role=Qt.UserRole + 1):
if role == Qt.CheckStateRole:
if (self.flags() & Qt.ItemIsAutoTristate and
value != Qt.PartiallyChecked):
for row in range(self.rowCount()):
for column in range(self.columnCount()):
child = self.child(row, column)
if child.data(role) is not None:
flags = self.flags()
self.setFlags(flags & ~Qt.ItemIsAutoTristate)
child.setData(value, role)
self.setFlags(flags)
model = self.model()
if model is not None:
parent = self
while True:
parent = parent.parent()
if (parent is not None and
parent.flags() & Qt.ItemIsAutoTristate):
model.dataChanged.emit(
parent.index(), parent.index(),
[Qt.CheckStateRole])
else:
break
super().setData(value, role)
def _childrenCheckState(self):
checked = unchecked = False
for row in range(self.rowCount()):
for column in range(self.columnCount()):
child = self.child(row, column)
value = child.data(Qt.CheckStateRole)
if value is None:
return
elif value == Qt.Unchecked:
unchecked = True
elif value == Qt.Checked:
checked = True
else:
return Qt.PartiallyChecked
if unchecked and checked:
return Qt.PartiallyChecked
if unchecked:
return Qt.Unchecked
elif checked:
return Qt.Checked
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1139 次 |
| 最近记录: |