简体   繁体   中英

Override Text in QStyledItemDelegate for QTreeView

I'm having an issue with overriding the text displayed for a QTreeView using a QStyledItemDelegate . When some condition is met following code is executed:

void MyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
  .
  .

        QStyleOptionViewItemV4 opt = option;
        initStyleOption(&opt, index);
        QString text = opt.text;
        text = text + QString("TEST");
        opt.text = text;

        QStyledItemDelegate::paint(painter, opt, index);
}

I confirmed in the debbugger that TEST is added to opt.text .
However, when I run my program and look at the TreeVuew it is still displaying the original text without the TEST string appended.

It seems that when I call QStyledItemDelegate::paint(painter, opt, index) , it's ignoring the change I've made to the opt parameter.

The default implementation of the QStyledItemDelegate::paint() method uses it's own QStyleOptionViewItem instance initialized with data from the model.

From the Qt 5.4.0 source code:

void QStyledItemDelegate::paint(QPainter *painter,
        const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    Q_ASSERT(index.isValid());

    QStyleOptionViewItem opt = option;
    initStyleOption(&opt, index);

    const QWidget *widget = QStyledItemDelegatePrivate::widget(option);
    QStyle *style = widget ? widget->style() : QApplication::style();
    style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, widget);
}

Solution:

Do not call the default implementation and implement your delegate's paint() method like this:

void MyDelegate::paint(QPainter* painter, const QStyleOptionViewItem & option, const QModelIndex & index) const
{
    QStyleOptionViewItem itemOption(option);

    initStyleOption(&itemOption, index);
    itemOption.text = "Test Text";  // override text

    QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &itemOption, painter, nullptr);
}

The alternative solution, if you want to change the displayed text in a view, is to override displayText() method.

Example for Qt5:

mydelegate.h

virtual QString displayText(const QVariant &value,
                            const QLocale &locale) const override;

mydelegate.cpp

QString MyDelegate::displayText(const QVariant &value,
                                          const QLocale &locale) const
{
    Q_UNUSED(locale)
    QString result = value.toString() + "TEST";
    return result;
}

doc link: https://doc.qt.io/qt-5/qstyleditemdelegate.html#displayText

Depending what type of delegates it is, I would also try to override the setEditorData() method or even the createEditor() (where you can add values different from your model). It is less time consuming than doing such operation in paint.

Otherwise, you can use something like that to draw your text where you want:

painter->drawText(option.rect, Qt::AlignJustify, text + "_test");

You probably have a reason for doing so, but it seems like something is wrong in your design if you want to add extra text on the fly?

Possible QStyledItemDelegate::paint picks a text directly from index.data( Qt::DisplayRole ).toString() . That's why text is not changed. You may debug through Qt sources to be sure.

I propose you to use QIdentityProxyModel to do such things. Delegates are not designed for such solutions. You just need to override 1 method. So your code should look like this:

class MyProxyModel : public QIdentityProxyModel
{
  // ...
};

QVariant MyProxyModel::data(const QModelIndex &index, int role) const override
{
  if (  /*Conditions when you don't want to change source text*/ )
    return QIdentityProxyModel::data( index, role );

  // Extra check for editors or other roles to return original data
  if ( role == Qt::EditRole || role != Qt::DisplayRole )
    return QIdentityProxyModel::data( index, role );

  const auto sourceIndex = mapToSource( index );
  const auto originalText = sourceModel()->data( sourceIndex, Qt::DisplayRole ).toString();
  const auto newText = QString( "%1 [TEST]" ).arg( originalText );

  return newText;
}

// Usage
auto yourModel = YourOriginalModel( this );
auto proxy = MyProxyModel( this );
proxy->setSourceModel( yourModel );
view->setModel( proxy );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM