使用模型和委托小部件向 QTableView 添加行 [英] Adding row to QTableView with model and and delegate widgets
问题描述
我正在尝试使用 QAbstractTableModel 和 QItemDelegate 向 QTableView 添加一行,其中小部件出现在添加的行中.从我读过的内容来看,我需要在添加行的每个项目上调用 .edit(index) 来调用创建小部件的 createEditor 但是我得到 edit:editing failed
I am trying to add a row to QTableView with a QAbstractTableModel and QItemDelegate where the widgets appear in the added row. From what I've read I need to call .edit(index) on each item of the added row to call createEditor where the widgets are created however I am getting edit: editing failed
QItemDelegate:
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:
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 填充它们?
How can I trigger the QItemDelegate's createEditor to create the widgets for the added row's items and setEditorData to populate them?
推荐答案
首先,您可以使用 openPersistentEditor
,就像您在 __init__
中所做的那样.
First of all, you could use openPersistentEditor
as you already did in the __init__
.
self.table.edit()
报错的原因有两个:
- 为了允许通过
edit()
编辑项目,flags()
函数必须被覆盖并提供Qt.ItemIsEditable
标志; - 你不能在同一个函数的不同索引上多次调用
edit()
;
- in order to allow editing of an item through
edit()
, theflags()
function must be overridden and provide theQt.ItemIsEditable
flag; - you cannot call
edit()
multiple times on different indexes within the same function;
然后,您的代码中还有其他重要问题:
Then, there are other important problems in your code:
- 您没有正确使用模型,因为
data()
没有实现; - 只要提供标准行为(访问
index.model()._data
不好),代理就应该使用模型的基本函数; setEditorData
没有必要,只要尊重以上几个方面:Qt根据数据类型和编辑器类自动设置数据;setData()
应该实现以正确设置模型上的数据,否则将无法访问新数据;- 模型结构的改变(比如创建一个新行)应该在模型类中完成;
- you're not correctly using the model, as
data()
is not implemented; - the delegates should use the base functions of the model whenever they provide standard behavior (accessing
index.model()._data
is not good); setEditorData
is unnecessary, as long as the above aspects are respected: Qt automatically sets the data based on the data type and the editor class;setData()
should be implemented in order to correctly set the data on the model, otherwise the new data won't be accessible;- changes in the model structure (like creating a new row) should be done in the model class;
这是您的代码的修订版:
Here is a revised version of your code:
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, option, 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, index, 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)
这篇关于使用模型和委托小部件向 QTableView 添加行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!