[PySide] QTableWidget/View edit trigger a dialog?

I would like the edit trigger of one of the columns in my table to create a modal dialog (and then feed the data from the dialog back to the widget/model). Is there a simple way to do that just using the tableWidget/View, or do I have to use a delegate for that?

I currently have a delegate for that, but given the relative simplicity of my table I was wondering it’s overkill and there is a simpler way to achieve this.

i dont believe so, QItemDelegate is how i’ve always done it.

Related question: I am creating a QDialog as the editor used by my delegate. It has a confirm and a cancel button. How should I handle the cancel button in my delegate class? Right now I have the cancel button connected to the dialog’s close() method. However when that gets called the setModelData() method on the delegate still gets called. Why is that? Should I connect the cancel button to a method on my delegate that calls self.closeEditor.emit() instead? Or should the setModelData() method validate the status of the dialog to determine whether to set or skip?

This is all new to me so if I’m approaching this the wrong way feel free to point that out as well.

try connecting to .reject() instead of close. The delegate editor should handle accept/reject

reject works, but when I call reject() in the dialog, setModelData() gets called in the delegate class. Should I check the status of the editor in setModelData and then determine whether to set the data or not, or is there a different approach that won’t trigger setModelData?

it may always call setModelData, with normal controls i don’t think theres a notion of accepted or rejected. For example, if oyu have a string value and the editor is a lineedit, even if you hit escape, it still calls setData on the model. So you should probably see if the dialog result() before calling setData()

dialog.result() returns the same thing when I hit accept or reject.

Here’s a simplified example using a listView. The dialog buttons connect to accept and reject, and the delegate’s setModelData queries the result() of the editor, which is always 0.

EDIT: I ended up just calling setResult() in the dialog before closing it and then checking the result in the delegate. That is working so far.

from PySide import QtCore, QtGui

class TestEditor(QtGui.QDialog):
    def __init__(self, parent=None):
        super(TestEditor, self).__init__(parent)
        self.setModal(True)

        self.field = QtGui.QLineEdit()
        bLayout = QtGui.QHBoxLayout()
        self.okButton = QtGui.QPushButton("Set")
        self.cancelButton = QtGui.QPushButton("Cancel")
        bLayout.addWidget(self.okButton)
        bLayout.addWidget(self.cancelButton)

        self.okButton.clicked.connect(self.accept)
        self.cancelButton.clicked.connect(self.reject)

        layout = QtGui.QVBoxLayout()
        layout.addWidget(self.field)
        layout.addLayout(bLayout)
        self.setLayout(layout)

    def showEvent(self, event):
        # Show the dialog at the current mouse position
        geom = self.frameGeometry()
        geom.moveCenter(QtGui.QCursor.pos())
        self.setGeometry(geom)
        super(TestEditor, self).showEvent(event)

    @property
    def text(self):
        return self.field.text()

class TestDelegate(QtGui.QItemDelegate):
    def __init__(self, parent=None):
        super(TestDelegate, self).__init__(parent)

    def createEditor(self, parent, option, index):
        editor = TestEditor(parent)
        return editor

    def setModelData(self, editor, model, index):
        """ Get the data from our custom editor and stuffs it into the model.
        """
        print "setModelData editor result: {0}".format(editor.result())
        model.setData(index, editor.text)

class TestListModel(QtCore.QAbstractListModel):
    def __init__(self, parent=None):
        super(TestListModel, self).__init__(parent)
        self._data = range(10)

    def rowCount(self, parent):
        return len(self._data)

    def data(self, index, role):
        if role == QtCore.Qt.DisplayRole:
            return self._data[index.row()]

    def setData(self, index, value, role=QtCore.Qt.EditRole):
        if role == QtCore.Qt.EditRole:
            self._data[index.row()] = value
            return True

        return False

    def flags(self, index):
        return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable

if __name__ == '__main__':
    import sys

    app = QtGui.QApplication(sys.argv)
    table = QtGui.QListView()
    table.show()
    table.setItemDelegate(TestDelegate())

    model = TestListModel()
    table.setModel(model)
    sys.exit(app.exec_())

https://srinikom.github.io/pyside-docs/PySide/QtGui/QDialog.html#PySide.QtGui.PySide.QtGui.QDialog.reject

Maybe a bug? calling setResult yourself as you’re doing is probably the best bet