1

The code below creates the single QTableView. There is a QItemDelegate is assigned as a PersistentEditor. There are two kind of editors created: QLineEdit is created for the column 0 and the 'QComboBox` is created for the column 1.

When the tableView is clicked I would like to get the instance of both editors: the instance of the LineEdit and the instance of comboBox. How to achieve this?

from PyQt4 import QtCore, QtGui
app = QtGui.QApplication([])

class Delegate(QtGui.QItemDelegate):
    def __init__(self):
        QtGui.QItemDelegate.__init__(self)

    def createEditor(self, parent, option, index):
        if index.column()==0:
            lineedit=QtGui.QLineEdit(parent)
            return lineedit

        elif index.column()==1:
            combo=QtGui.QComboBox(parent)
            return combo

    def setEditorData(self, editor, index):
        row = index.row()
        column = index.column()
        value = index.model().items[row][column]
        if isinstance(editor, QtGui.QComboBox):
            editor.addItems(['Somewhere','Over','The Rainbow'])
            editor.setCurrentIndex(index.row())
        if isinstance(editor, QtGui.QLineEdit):
            editor.setText('Somewhere over the rainbow')

class Model(QtCore.QAbstractTableModel):
    def __init__(self):
        QtCore.QAbstractTableModel.__init__(self)
        self.items = [[1, 'one', 'ONE'], [2, 'two', 'TWO'], [3, 'three', 'THREE']]

    def flags(self, index):
        return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable
    def rowCount(self, parent=QtCore.QModelIndex()):
        return 3 
    def columnCount(self, parent=QtCore.QModelIndex()):
        return 3

    def data(self, index, role):
        if not index.isValid(): return 
        row = index.row()
        column = index.column()
        if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
            return self.items[row][column]


def tableViewClicked(index):
    print 'clicked indedx:  %s'%index

tableModel=Model()
tableView=QtGui.QTableView() 
tableView.setModel(tableModel)
tableView.setItemDelegate(Delegate())
tableView.clicked.connect(tableViewClicked)

for row in range(tableModel.rowCount()):
    for column in range(tableModel.columnCount()):
        index=tableModel.index(row, column)
        tableView.openPersistentEditor(index)

tableView.show()
app.exec_()
alphanumeric
  • 17,967
  • 64
  • 244
  • 392
  • 1
    I'm not sure I understand your question exactly. There is only 1 instance of the delegate created. You created it and passed it to `setItemDelegate()`. If you want access to the editor widgets themselves, well you create those too in `Delegate.createEditor()`. Can you not just save a reference to both the instance of `Delegate`, and the editor widgets you create, and access as you please? – three_pineapples Apr 30 '16 at 00:58
  • Thanks for pointing out. I have edited my question to make it more clear. I would like to query both editors created for the column 0 and the column 1. – alphanumeric Apr 30 '16 at 03:43
  • `QItemDelegate` comes with `setModelData` and `setEditorData` methods. There should be a way to query the `editor` knowing the `index`. – alphanumeric May 04 '16 at 02:15
  • Personally I would just modify `createEditor` to store a reference for each `editor` in the model based on the `index`. You can then query as you like. – three_pineapples May 04 '16 at 02:19

1 Answers1

0

I recently set up something similar like this. This might be what you were after.

Step 1, create the delegate to do whatever it is you need, and store the QLineEdit as a variable. In the case below, I want a signal to emit every time the user leaves the QLineEdit.

class LineEditDelegate(QtWidgets.QStyledItemDelegate):
    on_focus_out = QtCore.Signal(object)

    def __init__(self, *args, **kwargs):
        super(LineEditDelegate, self).__init__(*args, **kwargs)
        self.line_edit = None

    def createEditor(self, parent, option, index):
        self.line_edit = QtWidgets.QLineEdit(parent=parent)

        self.line_edit.destroyed.connect(lambda: self._line_edit_left(index=index))

        return self.line_edit

    def _line_edit_left(self, index):
        """
        Triggers when line edit was closed / destroyed

        :param index: QModelIndex, index of edited item

        :return: None
        """

        self.on_focus_out.emit(index)

        return

Step 2, Create you QTableWidget and setup however you want, adding the delegate where you need it. In this example, on all items in column 0

self.table = QtWidgets.QTableWidget(parent=self.base_widget)
self.table.setRowCount(2)
self.table.setColumnCount(2)

self.line_edit_delegate = LineEditDelegate(self.main_window)
self.table.setItemDelegateForColumn(0, self.line_edit_delegate)

I also connect my function to the signal, fulfilling the purpose of this delegate.

self.line_edit_delegate.on_focus_out.connect(self._check_text)

Step 3, Getting the delegate item, i.e. the QLineEdit. First you'll need to get the item; you can do this in many ways such as:

item_0 = self.table.currentRow()
item_0 = self.table.currentItem()

or connecting through one of the QTableWidget's signals that pass through the QTableWidgetItem, row, or whatever:

self.table.itemClicked.connect(self.item_clicked)
self.table.itemDoubleClicked.connect(self.item_double_clicked)

Then with the QTableWidgetItem you can get the delegate, and then get the QLineEdit.

delegate = self.table.itemDelegate(self.table.indexFromItem(item_0))
delegate.line_edit

For my use, I wanted the user to add a new row and then have the QLineEdit get automatically selected for editing. This is what I used:

row_position = self.table.currentRow() + 1

item_0 = QtWidgets.QTableWidgetItem()
item_0.setFont(font)
self.table.setItem(row_position, 0, item_0)

self.table.openPersistentEditor(item_0)
delegate = self.table.itemDelegate(self.table.indexFromItem(item_0))
delegate.line_edit.setFocus()
Adam Sirrelle
  • 357
  • 8
  • 18