basic6
basic6

Reputation: 3811

How to use multiline text / linebreaks in QTableView/QAbstractTableModel?

I have subclassed QAbstractTableModel and QTabelView (and QSortFilterProxyModel) and I'd like to allow multi-line text to be displayed to and entered by the user in text cells (currently, hitting return will confirm the edit instead of inserting a line break).

There should be some simple flag to set, I just don't know which one...

Upvotes: 1

Views: 2172

Answers (2)

David Faure
David Faure

Reputation: 1997

QItemDelegate can actually draw the text over multiple lines (if it contains explicit '\n' characters), while the default QStyledItemDelegate doesn't do that (at least not on Linux, I didn't test other platforms). So we'll need to use QItemDelegate for the rendering.

But we also need to change the widget used for editing, which can't be a QLineEdit anymore, it needs to be a QPlainTextEdit. So we'll have to derive from QItemDelegate and change the type of widget being created for editing.

#ifndef MULTILINEDELEGATE_H
#define MULTILINEDELEGATE_H

#include <QItemDelegate>

class MultilineDelegate : public QItemDelegate
{
    Q_OBJECT
public:
    using QItemDelegate::QItemDelegate;

public:
    QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
    void setEditorData(QWidget *editor, const QModelIndex &index) const override;
    void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
};

#endif
#include "multilinedelegate.h"
#include <QPlainTextEdit>

QWidget *MultilineDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    Q_UNUSED(option);
    Q_UNUSED(index);
    return new QPlainTextEdit(parent);
}

void MultilineDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    if (auto *textEdit = qobject_cast<QPlainTextEdit *>(editor)) {
        textEdit->setPlainText(index.data(Qt::EditRole).toString());
    } else {
        QItemDelegate::setEditorData(editor, index);
    }
}

void MultilineDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    if (auto *textEdit = qobject_cast<QPlainTextEdit *>(editor)) {
        model->setData(index, textEdit->toPlainText());
    } else {
        QItemDelegate::setModelData(editor, model, index);
    }
}

And now all that remains to be done is using that delegate on the appropriate columns. For instance tableView->setItemDelegateForColumn(MyModel::AddressColumn, new MultilineDelegate(this));

This also looks better if the rows grow vertically as needed: tableView->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);

Tested with Qt 5.15, hopefully it should work with Qt 6 as well.

Upvotes: 2

Matthew
Matthew

Reputation: 2829

Not entirely sure what you are asking but I'll assume you already have your cell set up with a widget that can accept multi-line input (i.e. QTextEdit using setItem on your QTableView).

If you have that, I believe you would want to create a custom QItemDelegate derived class and override the default Enter behaviour to insert a line break rather than committing the delegate's data as is the default behaviour

See http://qt-project.org/doc/qt-4.8/qitemdelegate.html#eventFilter to get you started in the right direction.

Upvotes: 1

Related Questions