在 PySide/PyQt 中查看带有复选框列的 QStandardItemModel?
View QStandardItemModel with column of checkboxes in PySide/PyQt?
我有一个 QTreeView
的 QStandardItemModel
,并且希望一列仅为复选框(没有文本,只有复选框)。这 has been discussed 为 QAbstractItemModel
。我试图在那里实施解决方案(请参阅下面的 SSCCE),但在视图的第一行中只显示一个复选框。我不确定需要添加什么额外的魔法才能让复选框显示在每一行中。
请注意,如 this related question 所述,我想要一列复选框 没有文本字段 ,因此只需将 setCheckable(True)
应用于列是不够的,因为它会在复选框旁边留下一个(空的)文本字段。
SSCCE
# -*- coding: utf-8 -*-
from PySide import QtGui, QtCore
import sys
class CheckBoxDelegate(QtGui.QStyledItemDelegate):
def __init__(self, parent = None):
QtGui.QStyledItemDelegate.__init__(self, parent)
def createEditor(self, parent, option, index):
return None
def paint(self, painter, option, index):
checked = bool(index.model().data(index, QtCore.Qt.DisplayRole))
check_box_style_option = QtGui.QStyleOptionButton()
if (index.flags() & QtCore.Qt.ItemIsEditable) > 0:
check_box_style_option.state |= QtGui.QStyle.State_Enabled
else:
check_box_style_option.state |= QtGui.QStyle.State_ReadOnly
if checked:
check_box_style_option.state |= QtGui.QStyle.State_On
else:
check_box_style_option.state |= QtGui.QStyle.State_Off
check_box_style_option.rect = self.getCheckBoxRect(option)
QtGui.QApplication.style().drawControl(QtGui.QStyle.CE_CheckBox, check_box_style_option, painter)
def editorEvent(self, event, model, option, index):
if not (index.flags() & QtCore.Qt.ItemIsEditable) > 0:
return False
# Do not change the checkbox-state
if event.type() == QtCore.QEvent.MouseButtonRelease or event.type() == QtCore.QEvent.MouseButtonDblClick:
if event.button() != QtCore.Qt.LeftButton or not self.getCheckBoxRect(option).contains(event.pos()):
return False
if event.type() == QtCore.QEvent.MouseButtonDblClick:
return True
elif event.type() == QtCore.QEvent.KeyPress:
if event.key() != QtCore.Qt.Key_Space and event.key() != QtCore.Qt.Key_Select:
return False
else:
return False
# Change the checkbox-state
self.setModelData(None, model, index)
return True
def setModelData (self, editor, model, index):
newValue = not bool(index.model().data(index, QtCore.Qt.DisplayRole))
model.setData(index, newValue, QtCore.Qt.EditRole)
def getCheckBoxRect(self, option):
check_box_style_option = QtGui.QStyleOptionButton()
check_box_rect = QtGui.QApplication.style().subElementRect(QtGui.QStyle.SE_CheckBoxIndicator, check_box_style_option, None)
check_box_point = QtCore.QPoint (option.rect.x() +
option.rect.width() / 2 -
check_box_rect.width() / 2,
option.rect.y() +
option.rect.height() / 2 -
check_box_rect.height() / 2)
return QtCore.QRect(check_box_point, check_box_rect.size())
#BUILD THE TREE
app = QtGui.QApplication(sys.argv)
model = QtGui.QStandardItemModel()
model.setHorizontalHeaderLabels(['Title', 'Summary', 'Checkbox'])
rootItem = model.invisibleRootItem()
#Adding branches and leaves to root
item0 = [QtGui.QStandardItem('Title0'), QtGui.QStandardItem('Summary0')]
item00 = [QtGui.QStandardItem('Title00'), QtGui.QStandardItem('Summary00')]
rootItem.appendRow(item0)
item0[0].appendRow(item00)
treeView= QtGui.QTreeView()
treeView.setModel(model)
treeView.expandAll()
treeView.show()
#PUT THE CHECKBOX IN COLUMN 2
myDelegate = CheckBoxDelegate()
treeView.setItemDelegateForColumn(2, myDelegate)
sys.exit(app.exec_())
我认为您根本不需要项目委托。简单地考虑使用 QStandardItem::setFlags()
函数以及 Qt::ItemIsUserCheckable
标志,用于添加到树中的每个 QStandardItem
。
列数有问题:只有两列,顶级项目除外。委托设置在第三列,因此它只为顶级项目设置。
你定义你的行:
item1 = [QtGui.QStandardItem('Title1'), QtGui.QStandardItem('Summary1')]
很明显,这里只有两列。但在此之前,您将 header 标签设置为:
model.setHorizontalHeaderLabels(['Title', 'Summary', 'Checkbox'])
我猜这行设置了顶级项目有三列,但它对 child 项目没有任何影响。
如果你直接创建包含三个项目的行,你的问题就解决了:
item0 = [QtGui.QStandardItem('Title0'), QtGui.QStandardItem('Summary0'), QtGui.QStandardItem()]
item00 = [QtGui.QStandardItem('Title00'), QtGui.QStandardItem('Summary00'), QtGui.QStandardItem()]
我有一个 QTreeView
的 QStandardItemModel
,并且希望一列仅为复选框(没有文本,只有复选框)。这 has been discussed 为 QAbstractItemModel
。我试图在那里实施解决方案(请参阅下面的 SSCCE),但在视图的第一行中只显示一个复选框。我不确定需要添加什么额外的魔法才能让复选框显示在每一行中。
请注意,如 this related question 所述,我想要一列复选框 没有文本字段 ,因此只需将 setCheckable(True)
应用于列是不够的,因为它会在复选框旁边留下一个(空的)文本字段。
SSCCE
# -*- coding: utf-8 -*-
from PySide import QtGui, QtCore
import sys
class CheckBoxDelegate(QtGui.QStyledItemDelegate):
def __init__(self, parent = None):
QtGui.QStyledItemDelegate.__init__(self, parent)
def createEditor(self, parent, option, index):
return None
def paint(self, painter, option, index):
checked = bool(index.model().data(index, QtCore.Qt.DisplayRole))
check_box_style_option = QtGui.QStyleOptionButton()
if (index.flags() & QtCore.Qt.ItemIsEditable) > 0:
check_box_style_option.state |= QtGui.QStyle.State_Enabled
else:
check_box_style_option.state |= QtGui.QStyle.State_ReadOnly
if checked:
check_box_style_option.state |= QtGui.QStyle.State_On
else:
check_box_style_option.state |= QtGui.QStyle.State_Off
check_box_style_option.rect = self.getCheckBoxRect(option)
QtGui.QApplication.style().drawControl(QtGui.QStyle.CE_CheckBox, check_box_style_option, painter)
def editorEvent(self, event, model, option, index):
if not (index.flags() & QtCore.Qt.ItemIsEditable) > 0:
return False
# Do not change the checkbox-state
if event.type() == QtCore.QEvent.MouseButtonRelease or event.type() == QtCore.QEvent.MouseButtonDblClick:
if event.button() != QtCore.Qt.LeftButton or not self.getCheckBoxRect(option).contains(event.pos()):
return False
if event.type() == QtCore.QEvent.MouseButtonDblClick:
return True
elif event.type() == QtCore.QEvent.KeyPress:
if event.key() != QtCore.Qt.Key_Space and event.key() != QtCore.Qt.Key_Select:
return False
else:
return False
# Change the checkbox-state
self.setModelData(None, model, index)
return True
def setModelData (self, editor, model, index):
newValue = not bool(index.model().data(index, QtCore.Qt.DisplayRole))
model.setData(index, newValue, QtCore.Qt.EditRole)
def getCheckBoxRect(self, option):
check_box_style_option = QtGui.QStyleOptionButton()
check_box_rect = QtGui.QApplication.style().subElementRect(QtGui.QStyle.SE_CheckBoxIndicator, check_box_style_option, None)
check_box_point = QtCore.QPoint (option.rect.x() +
option.rect.width() / 2 -
check_box_rect.width() / 2,
option.rect.y() +
option.rect.height() / 2 -
check_box_rect.height() / 2)
return QtCore.QRect(check_box_point, check_box_rect.size())
#BUILD THE TREE
app = QtGui.QApplication(sys.argv)
model = QtGui.QStandardItemModel()
model.setHorizontalHeaderLabels(['Title', 'Summary', 'Checkbox'])
rootItem = model.invisibleRootItem()
#Adding branches and leaves to root
item0 = [QtGui.QStandardItem('Title0'), QtGui.QStandardItem('Summary0')]
item00 = [QtGui.QStandardItem('Title00'), QtGui.QStandardItem('Summary00')]
rootItem.appendRow(item0)
item0[0].appendRow(item00)
treeView= QtGui.QTreeView()
treeView.setModel(model)
treeView.expandAll()
treeView.show()
#PUT THE CHECKBOX IN COLUMN 2
myDelegate = CheckBoxDelegate()
treeView.setItemDelegateForColumn(2, myDelegate)
sys.exit(app.exec_())
我认为您根本不需要项目委托。简单地考虑使用 QStandardItem::setFlags()
函数以及 Qt::ItemIsUserCheckable
标志,用于添加到树中的每个 QStandardItem
。
列数有问题:只有两列,顶级项目除外。委托设置在第三列,因此它只为顶级项目设置。
你定义你的行:
item1 = [QtGui.QStandardItem('Title1'), QtGui.QStandardItem('Summary1')]
很明显,这里只有两列。但在此之前,您将 header 标签设置为:
model.setHorizontalHeaderLabels(['Title', 'Summary', 'Checkbox'])
我猜这行设置了顶级项目有三列,但它对 child 项目没有任何影响。
如果你直接创建包含三个项目的行,你的问题就解决了:
item0 = [QtGui.QStandardItem('Title0'), QtGui.QStandardItem('Summary0'), QtGui.QStandardItem()]
item00 = [QtGui.QStandardItem('Title00'), QtGui.QStandardItem('Summary00'), QtGui.QStandardItem()]