0
votes

I need to intercept key events emitted when user is editing a cell in QTableWidget. Is there a simple way of doing this? I was thinking of installing event filter but I do not know how to get reference to the editor widget. Or do I need to somehow reimplement QItemDelegate? This seems as overkill to me and not sure how to do that, what exactly needs to be reimplemented. Or is there another way?

I need this because for example when the user presses left/right cursor key, I want to skip to the next cell on the left/right.

2
Are you sure you want that behaviour? It would make it impossible to move within the text during editing (e.g. to delete an earlier character).ekhumoro
Actually this is something what MS Excel does. When I know how to do this, I can do more fine-tuning, e.g. when you press F2, then you can move with arrows inside the edited text, etc. However it seems I already have solution. I will post it shortly.V.K.

2 Answers

2
votes

It seems I have finally figured it out and it works exactly as I needed. Here is a solution in PySide (C++ is analogous) using overriding of QStyledItemDelegate. It seemed to me as overkill at first, but it was not that bad.

fromPySide import QtCore, QtGui

class LineEditDelegate(QtGui.QStyledItemDelegate):

    moveCurrentCellBy = QtCore.Signal(int, int)

    def __init__(self, parent=None):
        super(LineEditDelegate, self).__init__(parent)

    def createEditor(self, parent, option, index):
        self.editor = QtGui.QLineEdit(parent)
        self.editor.setFrame(False)
        self.editor.installEventFilter(self)
        return self.editor

    def setEditorData(self, editor, index):
        value = index.model().data(index, QtCore.Qt.EditRole)
        editor.setText(value)

    def setModelData(self, editor, model, index):
        value = editor.text()
        model.setData(index, value, QtCore.Qt.EditRole)

    def updateEditorGeometry(self, editor, option, index):
        editor.setGeometry(option.rect)

    def eventFilter(self, target, event):
        if target is self.editor:
            if event.type() == QtCore.QEvent.KeyPress:
                moveCell, row, column = False, 0, 0
                if event.key() in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter, QtCore.Qt.Key_Down):
                    moveCell, row, column = True, 1, 0
                if event.key() in (QtCore.Qt.Key_Right, QtCore.Qt.Key_Tab):
                    moveCell, row, column = True, 0, 1
                if event.key() in (QtCore.Qt.Key_Left, QtCore.Qt.Key_Backtab):
                    moveCell, row, column = True, 0, -1
                if event.key() == QtCore.Qt.Key_Up:
                    moveCell, row, column = True, -1, 0
                if moveCell:
                    self.commitData.emit(self.editor)
                    self.closeEditor.emit(self.editor, QtGui.QAbstractItemDelegate.NoHint)
                    self.moveCurrentCellBy.emit(row, column)
                    return True
        return False     


class TableWidget(QtGui.QTableWidget):
    def __init__(self, parent=None):
        super(TableWidget, self).__init__(parent)
        delegate = LineEditDelegate()
        delegate.moveCurrentCellBy.connect(self.moveCurrentCellBy)
        self.setItemDelegate(delegate)

    def moveCurrentCellBy(self, rowStep, columnStep):
        row = self.currentRow() + rowStep
        column = self.currentColumn() + columnStep
        if row >= self.rowCount():
            self.setRowCount(row + 1)
        if column >= self.columnCount():
            self.setColumnCount(column + 1)
        self.setCurrentCell(row, column)
0
votes

Or alternatively you could use cellClicked signal like this:

  connect(ui->tbControl,SIGNAL(cellClicked(int,int)),this,SLOT(detectCellSelectionGraph(int,int)));