How to get the background color returned by the model takes precedence over the style

I have a QTreeView

render QAbstractItemModel

where I would like to set the background of certain cells based on data in a model. I am returning QBrush

from model::data(Qt::BackgroundColorRole)

and working until I apply the style to the element.

Setting any style on the element (even something that has nothing to do with the background color, like styling the border) overrides the color I return from the model (calls to the model asking for the background color). That is, the view behaves as if the model never returned any color.

I am using Qt 4.8 and I cannot upgrade to a later version.

Is there a way to make the color returned from the model take precedence over the style? Why Qt behaves in such a weird way: The model has a narrower granularity and knows a way more than style can know why style takes precedence. After all, the model shouldn't return a color for each cell - just a few specific ones?

I guess this is a bug in Qt, I opened a bug report that reproduces with this code:

#include <QtCore/qabstractitemmodel.h>
#include <QtGui/qtreeview.h>
#include <QtGui/qtableview.h>
#include <QtGui/qapplication.h>

class MyModel : public QAbstractItemModel
{
public:
    MyModel(QObject *parent) :QAbstractItemModel(parent){}

    int rowCount(const QModelIndex &parent = QModelIndex()) const
    { return 2; }
    int columnCount(const QModelIndex &parent = QModelIndex()) const
    { return parent.isValid() ? 0 : 2; }
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
    {
        if(index.row() >= 0 && index.column() >= 0)
        {
            switch(role)
            {
            case Qt::DisplayRole:
                return QString("a");
            case Qt::BackgroundRole:
                return QBrush(QColor(255 * index.row(), 255 * index.column(), 0));
            default:
                break;
            }
        }
        return QVariant();
    }
    virtual QModelIndex index(int pos, int column, const QModelIndex &parent = QModelIndex()) const
    { return createIndex(pos, column, 0); }
    virtual QModelIndex parent(const QModelIndex &child) const
    { return QModelIndex(); }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QTreeView view;
    MyModel myModel(0);
    view.setModel(&myModel);
    view.show();

    //a.setStyleSheet("QTreeView::item { border: 1px solid black; }");
    return a.exec();
}

      

If you uncomment the line before returning, all backgrounds are gone.

This is what I get when the line is commented

And this when I uncomment it

0


source to share


1 answer


I found a workaround - this is some additional code and IMHO it should have been handled by Qt itself, but at least there is a way to overlay the background on the default rendering, that is, I don't need to override everything the default delegate does ( QStyledItemDelegate

) :

    void Delegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        QVariant bg = index.data(Qt::BackgroundRole);
        if(bg.isValid())                // workaround for Qt bug https://bugreports.qt.io/browse/QTBUG-46216
            painter->fillRect(option.rect, bg.value<QBrush>());
        QStyledItemDelegate::paint(painter, option, index);
    }

      



If the background returned by the model is somewhat transparent (I used an alpha value of 50), it will blend well over the background of the style so that interlaced color or similar material is still visible.

Interestingly, however, I also applied the same trick to the header (in reimplemented QHeaderView::paintSection

) and it didn't work - my background is displayed until I call QHeaderView::paintSection

- if so, my call is painter->fillRect

ignored. I'll post it as a separate question.

+1


source







All Articles