QItemDelegate 复选框
Posted
技术标签:
【中文标题】QItemDelegate 复选框【英文标题】:QItemDelegate CheckBox 【发布时间】:2017-12-30 01:08:22 【问题描述】:所以,我在 Maya 中使用 python 和 PySide2 来制作自定义工具。
我有一个模型(QTableModel)和一个 QTableView。
模型中的每一行都会有一堆信息和一个复选框。
我必须做一个 QItemDelegate 并将其用作复选框。没事儿。我无法确定该委托是否已选中。
我通过模型迭代获取其数据(将其存储在节点中的 Maya 场景中)
data = []
rows = self.rowCount(1) #self is the model in this snnipet
for row in range(rows):
array = []
for column in range (6): #6 for the fixed number of columns
info = index.data()
array.append(index.data())
data.append(array)
碰巧每一行的第一个项目是一个复选框(委托)。在最终的数据数组中,当我真的想获得它的状态时,我最终得到了实际的 QItemDelegate 对象,检查与否,但它没有 isChecked() 方法。
关于如何获得它的想法?
非常感谢!
######## 编辑 1因此,该模型确实具有 cmets 中提到的标志:
def flags(self, index):
return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsUserCheckable
我认为我做错了代表,我承认,我在网上找到了这个片段,我试图理解它....但它是这样的:
class CBDelegate(QItemDelegate):
def __init__(self, parent):
QItemDelegate.__init__(self, parent)
def paint(self, painter, option, index):
self.cb = QCheckBox()
try:
self.cb.setChecked(index.data())
except:
pass
if not self.parent().indexWidget(index):
self.parent().setIndexWidget(index, self.cb)
然后,在 TableView:
self.setItemDelegateForColumn(0, CBDelegate(self))
有帮助吗? (如果你有 Maya 2017,我可以给你整个代码......这有点乱,因为我把它用作学习练习!
谢谢。
############ 编辑 2表格视图:
class Table(QTableView):
def __init__(self, *args, **kwargs):
QTableView.__init__(self, *args, **kwargs)
# Set the delegate for column 0 of our table
#self.setItemDelegateForColumn(6, ButtonDelegate(self)) #problem for another time
self.setItemDelegateForColumn(0, CBDelegate(self))
型号:
class Model(QtCore.QAbstractTableModel):
def __init__(self, cycles = [[]], headers = [], parent = None):
QtCore.QAbstractTableModel.__init__(self, parent)
self.cycles = cycles
self.headers = headers
def rowCount(self, parent):
return len(self.cycles)
def columnCount(self, parent):
return len(self.cycles[0])
def flags(self, index):
return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsUserCheckable
def data(self, index, role):
if role == QtCore.Qt.DisplayRole:
row = index.row()
column = index.column()
value = self.cycles[row][column]
return value
if role == QtCore.Qt.EditRole:
row = index.row()
column = index.column()
return self.cycles[row][column]
if (role == QtCore.Qt.TextAlignmentRole):
return QtCore.Qt.AlignCenter;
def setData(self, index, value, role = QtCore.Qt.EditRole):
change = False
if role == QtCore.Qt.EditRole:
row = index.row()
column = index.column()
value = value
if (column == 1) or (column == 4):
try:
str(value)
change = True
except:
pm.warning("Not a valid name")
change = False
elif (column == 2):
try:
int(value)
change = True
except:
pm.warning("Not a valid frame")
change = False
elif (column == 3):
try:
int(value)
change = True
except:
pm.warning("Not a valid frame")
change = False
elif (column == 5):
try:
int(value)
change = True
except:
pm.warning("Not a valid version number")
change = False
if change:
self.cycles[row][column] = value
self.dataChanged.emit(row, column)
return True
return False
def headerData(self, section, orientation, role):
if role == QtCore.Qt.DisplayRole:
if orientation == QtCore.Qt.Horizontal:
return self.headers[section]
def insertRows(self, position, rows, values = [] , parent = QtCore.QModelIndex()):
self.beginInsertRows(parent, position, position+rows-1)
self.cycles.insert(position, values)
self.endInsertRows()
self.getData()
def getData(self):
rows = self.rowCount(1)
data = []
for row in range(rows):
array = []
for column in range (6):
index = self.index(row, column)
info = index.data()
if type(info) == bool:
array.append(info)
elif type(info) == QItemDelegate:
val_is_checked = index.data(QtCore.Qt.CheckStateRole) != QtCore.Qt.Unchecked
array.append(val_is_checked)
else:
info = str(info)
array.append(info)
array.append("del")
data.append(array)
dic =
for item in data:
dic[item[1]]=item
for key in dic:
print key, dic[key]
#this from pickle
#newData = data2String(dic)
# and this is what I wanna save inside Maya
#pm.setAttr("cycleAnimationListNode.cycles", newData)
代表在上面的编辑 1 中。
那么我猜你仍然需要循环和标题来启动这个模型:
headers = ["Select", " Cycle Name ", " Start ", " End ", "Info", "Version", " Del "]
cycles = [[False,"idle","1","70","cool information","0", "deleteBtnPlaceHolder"]]
我希望这样做。
谢谢。
##### 编辑 3我在模型中有这个自定义方法:
def getData(self):
rows = self.rowCount(1)
data = []
for row in range(rows):
array = []
for column in range (6):
index = self.index(row, column)
info = index.data()
array.append(info)
data.append(array)
dic =
for item in data:
dic[item[1]]=item
print ""
print "data:"
print ''
for key in dic:
print(key, dic[key])
我使用它将模型转换为字典,因此我可以将其序列化并存储为 Autodesk Maya 中节点的字符串属性。它运行正常,但它从第一列获得的信息始终为无。我必须以不同的方式检索它吗?
【问题讨论】:
试用:val_is_checked = index.data(Qt.CheckStateRole) != Qt.Unchecked
嘿!感谢您的评论。看起来它有效,但它只返回 True ,即使它没有被选中。想法?
您是否在模型中启用了标志Qt::ItemIsUserCheckable
,如果您提供minimal reproducible example,它会对您有所帮助
该标志已设置。我可能在设置 QItemDelegate 时遇到问题。我对此很陌生。 ..
虽然我对这个主题很陌生,但我认为你有能力提供minimal reproducible example,不幸的是,没有算命先生,所以你采样的代码我们不能帮你。 :P
【参考方案1】:
如果要显示QCheckBox
,则无需使用委托,只需正确启用标志Qt::ItemIsUserCheckable
,此外必须通过setData()
保存信息,因为在您的代码中信息丢失,因为存储在以下部分中显示了具有这些修改的模型:
更新:
以前禁用第一列角色Qt::DisplayRole
的数据方法的返回,因为它将文本放置在表格中,这对我来说是不必要的,现在我启用了它,但文本不显示我已放置一个删除文本的委托
from PySide2.QtWidgets import *
from PySide2.QtCore import *
class Model(QAbstractTableModel):
def __init__(self, cycles = [[]], headers = [], parent = None):
QAbstractTableModel.__init__(self, parent)
self.cycles = cycles
self.headers = headers
self.values_checked = []
def rowCount(self, parent):
return len(self.cycles)
def columnCount(self, parent):
return len(self.cycles[0])
def flags(self, index):
fl = Qt.ItemIsEnabled | Qt.ItemIsSelectable
if index.column() == 0:
fl |= Qt.ItemIsUserCheckable
else:
fl |= Qt.ItemIsEditable
return fl
def data(self, index, role):
if not index.isValid():
return
row = index.row()
column = index.column()
if role == Qt.DisplayRole:
value = self.cycles[row][column]
return value
elif role == Qt.TextAlignmentRole:
return Qt.AlignCenter;
elif role == Qt.CheckStateRole and column==0:
return Qt.Checked if self.cycles[row][column] else Qt.Unchecked
def setData(self, index, value, role = Qt.EditRole):
change = False
row = index.row()
column = index.column()
if role == Qt.CheckStateRole:
value = value != Qt.Unchecked
change = True
if role == Qt.EditRole:
if (column == 1) or (column == 4):
try:
str(value)
change = True
except:
pm.warning("Not a valid name")
change = False
elif (column == 2):
try:
int(value)
change = True
except:
pm.warning("Not a valid frame")
change = False
elif (column == 3):
try:
int(value)
change = True
except:
pm.warning("Not a valid frame")
change = False
elif (column == 5):
try:
int(value)
change = True
except:
pm.warning("Not a valid version number")
change = False
if change:
self.cycles[row][column] = value
self.dataChanged.emit(row, column)
return True
return False
def headerData(self, section, orientation, role):
if role == Qt.DisplayRole:
if orientation == Qt.Horizontal:
return self.headers[section]
def insertRows(self, position, rows, values = [] , parent =QModelIndex()):
self.beginInsertRows(parent, position, position+rows-1)
self.cycles.insert(position, values)
self.endInsertRows()
self.getData()
def roleNames(self):
roles = QAbstractTableModel.roleNames(self)
roles["Checked"] = Qt.CheckStateRole
return roles
def getData(self):
rows = self.rowCount(1)
data = []
for row in range(rows):
array = []
for column in range (6):
index = self.index(row, column)
info = index.data()
array.append(info)
data.append(array)
dic =
for item in data:
dic[item[1]]=item
print("")
print("data:")
print('')
for key in dic:
print(key, dic[key])
class EmptyDelegate(QStyledItemDelegate):
def paint(self, painter, option, index):
opt = QStyleOptionViewItem(option)
self.initStyleOption(opt, index)
opt.text = ""
QApplication.style().drawControl(QStyle.CE_ItemViewItem, opt, painter)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
w = QTableView()
w.setItemDelegateForColumn(0, EmptyDelegate(w))
headers = ["Select", " Cycle Name ", " Start ", " End ", "Info", "Version", " Del "]
cycles = [[True,"idle","1","70","cool information","0", "deleteBtnPlaceHolder"]]
model = Model(cycles, headers)
w.setModel(model)
w.show()
sys.exit(app.exec_())
【讨论】:
一切顺利。唯一的问题是 thi:将 thie 方法设置为模型的自定义方法: def getData(self): rows = self.rowCount(1) data = [] for row in range(rows): array = [] for column in range (6): index = self. index(row, column) info = index.data() array.append(info) data.append(array) dic = for item in data: dic[item[1]]=item print "" print "data: " print '' for key in dic: print(key, dic[key]) 我得到的复选框单元格的信息是无...即使它说它在 setData 方法中更改为真或假... @MendelReis 现在更新答案并更正这些错误。 @MendelReis 更新代码在gist.github.com/eyllanesc/a4caf9b474d8e0c21df3a7d3c2a54a2c,别忘了把我的答案标记为正确以上是关于QItemDelegate 复选框的主要内容,如果未能解决你的问题,请参考以下文章
QComboBox实现复选功能(三种方法:嵌套QListWidget, 设置QStandardItemModel, 设置Delegate)