Question

I have a QTableView which has some QString based items in its model. I implemented setData in my table model, so editing is working (I can change the data in the cell, setData is called to update the model, and the table is properly updated).

Currently setData is only called when the user is done with editing, e.g. after they hit Enter or click out of the text entry box to finalize the text entry. I want to update other other parts of the table while the user is typing/editing into the text edit control instead of after they're done and the edited contents are finalized.

A simple example of what I want to have is for the next table cell to display a count of how many characters have been entered into the cell being edited, but to do this as the user is typing/editing the cell contents, not just after the edit is finalized and setData is called.

Any pointers to what I should be looking for? Thanks!

Was it helpful?

Solution

You can subclass QStyledItemDelegate and commit the data whenever something changes, and then set that delegate for the view with QAbstractItemView::setDelegateForColumn.

class MyDelegate : public QStyledItemDelegate {
   QSignalMapper *mapper;
public:
   MyDelegate(QObject*parent = 0)
     : QStyledItemDelegate(parent)
     , mapper(new QSignalMapper(this))
   {
       connect(mapper, SIGNAL(mapped(QWidget*)), SIGNAL(commitData(QWidget*)));
   }
   QWidget * createEditor(QWidget * parent, const QStyleOptionViewItem & option,
             const QModelIndex & index ) const
   {
       QWidget *editor = QStyledItemDelegate::createEditor(parent, option, index);
       if(qobject_cast<QLineEdit*>(editor)) {
           connect(editor, SIGNAL(textChanged(QString)), mapper, SLOT(map()));
           mapper->setMapping(editor, editor);
       }
       return editor;
   }
};

OTHER TIPS

The answer offered by @alexisdm did not work for me when I needed a persistent editor enabled by QAbstractTableModel::setPersistentEditor(QModelIndex()).

The following solves this problem:

class Delegate : public QStyledItemDelegate 
{
    Q_OBJECT
public: 

    // ... omitted for brevity

    QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
                          const QModelIndex &index) const override 
    {
        auto *editor = static_cast<QLineEdit*>(
                            QStyledItemDelegate::createEditor(parent, option, index));
        if (editor) {
            connect(editor,
                    &QLineEdit::textChanged,
                    [=] (const QString &)
            {
                const_cast<Delegate*>(this)->commitData(editor);
            });
        }
        return editor;   
    }

    // ... omitted for brevity
};

We simply cast the constness from this and make it commit data for the editor.

Note that in the lambda we capture the editor variable by value [=] because otherwise, capturing with reference would make the value of editor undefined when the function runs out of scope.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top