Code is almost complete. Here's the deal:
It is python and PySide. I have a QAbstractTableModel and a QTableView.
I cant get deleting rows correctly. I think the problem is somewhere in the indexes of the rows onde I delete one of them...
here is the button delegate I use:
class ButtonDelegate(QItemDelegate):
def __init__(self, parent):
QItemDelegate.__init__(self, parent)
def paint(self, painter, option, index):
widget = QWidget()
layout = QHBoxLayout()
widget.setLayout(layout)
btn = QPushButton("X")
btn.clicked.connect(partial(self.parent().cellButtonClicked, index))
layout.addWidget(btn)
layout.setContentsMargins(2,2,2,2)
if not self.parent().indexWidget(index):
self.parent().setIndexWidget(index, widget)
here's the cellButtonClicked method, it is under the table view:
class Table(QTableView):
def __init__(self, *args, **kwargs):
QTableView.__init__(self, *args, **kwargs)
self.setItemDelegateForColumn(6, ButtonDelegate(self))
self.setItemDelegateForColumn(0, EmptyDelegate(self))
self.setSortingEnabled(True)
def cellButtonClicked(self, index, *args):
model = self.model()
model.removeRow(index.row())
and here is the model removeRow Method:
def removeRow(self, row, parent = QtCore.QModelIndex()):
self.beginRemoveRows(parent, row, row)
array = []
for i in range(7):
if i == 0:
array.append(self.index(row, i).data())
else:
array.append(str(self.index(row, i).data()))
self.cycles.remove(array)
self.endRemoveRows()
# update custom node in maya.
self.getData()
I think that, mainly, the problem is that when I delete a row it does not update the indexes of the model. So when I click again in any delete button it starts de removeRow() with an index the does no match the rowCount of the model anymore, therefore I can't build the array to be removed from the model data.
Did it make sense? if you need more code, tell me what you need.
The problem is caused because you have set the value of the row when you have created each delegate, so its value is not updated.
A possible solution is to use a lambda function to pass a QPersistenModelIndex
associated with the temporary QModelIndex
, but I have seen that there is an unexpected behavior that is creating a selection, so I called clearSelection()
.
It is not necessary to connect to the cellButtonClicked slot since you can directly access the model using QModelIndex or QPersistenModelIndex.
class ButtonDelegate(QItemDelegate):
def __init__(self, parent):
QItemDelegate.__init__(self, parent)
def paint(self, painter, option, index):
widget = QWidget()
layout = QHBoxLayout()
widget.setLayout(layout)
btn = QPushButton("X")
ix = QPersistentModelIndex(index)
btn.clicked.connect(lambda ix = ix : self.onClicked(ix))
layout.addWidget(btn)
layout.setContentsMargins(2,2,2,2)
if not self.parent().indexWidget(index):
self.parent().setIndexWidget(index, widget)
def onClicked(self, ix):
model = ix.model()
model.removeRow(ix.row())
self.parent().clearSelection()
Another option is to handle the clicked events through editorEvent
since the provided QModelIndex
has updated values as shown below:
class ButtonDelegate(QStyledItemDelegate):
def __init__(self, parent):
QStyledItemDelegate.__init__(self, parent)
self.state = QStyle.State_Enabled
def paint(self, painter, option, index):
button = QStyleOptionButton()
button.rect = self.adjustRect(option.rect)
button.text = "X"
button.state = self.state
QApplication.style().drawControl(QStyle.CE_PushButton, button, painter)
def editorEvent(self, event, model, option, index):
if event.type() == QEvent.Type.MouseButtonPress:
self.state = QStyle.State_On
return True
elif event.type() == QEvent.Type.MouseButtonRelease:
r = self.adjustRect(option.rect)
if r.contains(event.pos()):
model.removeRow(index.row())
self.state = QStyle.State_Enabled
return True
@staticmethod
def adjustRect(rect):
r = QRect(rect)
margin = QPoint(2, 2)
r.translate(margin)
r.setSize(r.size()-2*QSize(margin.x(), margin.y()))
return r
In addition to this it is not necessary to iterate through data(), we can delete the row directly:
def removeRow(self, row, parent=QModelIndex()):
self.beginRemoveRows(parent, row, row)
self.cycles.remove(self.cycles[row])
self.endRemoveRows()
self.getData()
In the following link both options are implemented.