问题描述
我正在尝试使用 QAbstractTableModel 和 QItemDelegate 向 QTableView 添加一行,其中小部件出现在添加的行中。从我读过的内容来看,我需要在添加行的每个项目上调用 .edit(index) 来调用 createEditor,在其中创建小部件,但是我得到了 edit: editing failed
QItemDelegate:
class Delegate(QItemDelegate):
def __init__(self):
QItemDelegate.__init__(self)
self.type_items = ["1","2","3"]
def createEditor(self,parent,option,index):
# COMBOBOX,LINEEDIT,TIMEDIT
if index.column() == 0:
comboBox = QComboBox(parent)
for text in self.type_items:
comboBox.addItem(text,(index.row(),index.column()))
return comboBox
elif index.column() == 1:
lineEdit = QLineEdit(parent)
return lineEdit
elif index.column() == 2:
timeEdit = QTimeEdit(parent)
return timeEdit
def setEditorData(self,editor,index):
value = index.model()._data[index.row()][index.column()]
if index.column() == 0:
editor.setCurrentIndex(self.type_items.index(value))
elif index.column() == 1:
editor.setText(str(value))
elif index.column() == 2:
editor.setTime(value)
QAbstractTableModel:
class TableModel(QAbstractTableModel):
def __init__(self,data):
super(TableModel,self).__init__()
self._data = data
def data(self,index,role):
pass
def rowCount(self,index=None):
return len(self._data)
def columnCount(self,index=None):
return len(self._data[0])
主要内容:
class MainWindow(QMainWindow):
def __init__(self,parent=None):
super(MainWindow,self).__init__(parent)
localWidget = QWidget()
self.table = QTableView(localWidget)
data = [["1","Hi",QTime(2,1)],["2","Hello",QTime(3,0)]]
self.model = TableModel(data)
self.table.setModel(self.model)
self.table.setItemDelegate(Delegate())
self.add_row = QPushButton("Add Row",localWidget)
self.add_row.clicked.connect(self.addRow)
for row in range(self.model.rowCount()):
for column in range(self.model.columnCount()):
index = self.model.index(row,column)
self.table.openPersistentEditor(index)
layout_v = QVBoxLayout()
layout_v.addWidget(self.table)
layout_v.addWidget(self.add_row)
localWidget.setLayout(layout_v)
self.setCentralWidget(localWidget)
self.show()
def addRow(self):
new_row_data = ["3","Howdy",QTime(9,0)]
self.model.beginInsertRows(QModelIndex(),self.model.rowCount(),self.model.rowCount())
self.model._data.append(new_row_data)
self.model.endInsertRows()
for i in range(len(new_row_data)):
index = self.table.model().index(self.model.rowCount()-1,i)
self.table.edit(index)
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
如何触发 QItemDelegate 的 createEditor 为添加的行项目创建小部件并使用 setEditorData 填充它们?
解决方法
首先,您可以像在 openPersistentEditor
中那样使用 __init__
。
self.table.edit()
中的错误有两个原因:
- 为了允许通过
edit()
编辑项目,必须覆盖flags()
函数并提供Qt.ItemIsEditable
标志; - 您不能在同一函数内对不同索引多次调用
edit()
;
然后,您的代码中还有其他重要问题:
- 您没有正确使用模型,因为
data()
没有实现; - 只要提供标准行为(访问
index.model()._data
不好),代理就应该使用模型的基本函数; -
setEditorData
是不必要的,只要尊重以上方面:Qt 自动根据数据类型和编辑器类设置数据; -
setData()
应该被实现以正确设置模型上的数据,否则新数据将无法访问; - 模型结构的改变(比如创建一个新行)应该在模型类中完成;
这是您的代码的修订版:
class Delegate(QItemDelegate):
def __init__(self):
QItemDelegate.__init__(self)
self.type_items = ["1","2","3"]
def createEditor(self,parent,option,index):
if index.column() == 0:
comboBox = QComboBox(parent)
for text in self.type_items:
comboBox.addItem(text,(index.row(),index.column()))
return comboBox
# no need to check for the other columns,as Qt automatically creates a
# QLineEdit for string values and QTimeEdit for QTime values;
return super().createEditor(parent,index)
# no setEditorData() required
class TableModel(QAbstractTableModel):
def __init__(self,data):
super(TableModel,self).__init__()
self._data = data
def appendRowData(self,data):
self.beginInsertRows(QModelIndex(),self.rowCount(),self.rowCount())
self._data.append(data)
self.endInsertRows()
def data(self,index,role=Qt.DisplayRole):
if role in (Qt.DisplayRole,Qt.EditRole):
return self._data[index.row()][index.column()]
def setData(self,value,role=Qt.EditRole):
if role == Qt.EditRole:
self._data[index.row()][index.column()] = value
self.dataChanged.emit(index,index)
return True
return False
def rowCount(self,index=None):
return len(self._data)
def columnCount(self,index=None):
return len(self._data[0])
def flags(self,index):
# allow editing of the index
return super().flags(index) | Qt.ItemIsEditable
class MainWindow(QMainWindow):
# ...
def addRow(self):
row = self.model.rowCount()
new_row_data = ["3","Howdy",QTime(9,0)]
self.model.appendRowData(new_row_data)
for i in range(self.model.columnCount()):
index = self.model.index(row,i)
self.table.openPersistentEditor(index)