为QTreeView覆盖QStyledItemDelegate中的文本

Override Text in QStyledItemDelegate for QTreeView

本文关键字:文本 QStyledItemDelegate QTreeView 覆盖      更新时间:2023-10-16

使用QStyledItemDelegate覆盖为QTreeView显示的文本时遇到问题。当满足某些条件时,执行以下代码:

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);
}

我在debbug中确认TEST已添加到opt.text
但是,当我运行程序并查看TreeVuew时,它仍然显示原始文本,而没有附加TESTstring

当我调用QStyledItemDelegate::paint(painter, opt, index)时,它似乎忽略了我对opt参数所做的更改。

QStyledItemDelegate::paint()方法的默认实现使用它自己的QStyleOptionViewItem实例,该实例是用模型中的数据初始化的。

来自Qt 5.4.0的源代码:

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);
}

解决方案:

不要像这样调用默认实现并实现您的代表的paint()方法:

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);
}

如果要更改视图中显示的文本,另一种解决方案是覆盖displayText()方法。

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;
}

文档链接:https://doc.qt.io/qt-5/qstyleditemdelegate.html#displayText

根据委托的类型,我也会尝试覆盖setEditorData()方法,甚至createEditor()(在其中可以添加与模型不同的值)。这比在油漆中进行这样的操作耗时更少。

否则,你可以用类似的东西把文本画到你想要的地方:

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

你这样做可能有原因,但如果你想在运行中添加额外的文本,你的设计似乎有问题?

可能的QStyledItemDelegate::paint直接从index.data( Qt::DisplayRole ).toString()中选取文本。这就是为什么文本没有更改。您可以通过Qt源进行调试以确定。

我建议你用QIdentityProxyModel来做这样的事情。代表不是为这样的解决方案而设计的。您只需要覆盖1个方法。所以你的代码应该是这样的:

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 );