How can I get the background color returned by model take precedence over the style

守給你的承諾、 提交于 2019-12-23 05:41:18

问题


I have a QTreeView rendering QAbstractItemModel, where I would like to set the background of certain cells based on the data in the model. I return QBrush from model::data(Qt::BackgroundColorRole) and it works until I apply a style to an item.

Setting any style to the item (even something that has nothing to do with background color, e.g. styling the border) overrides the color I return from the model (the calls to the model querying the background color are made). I.e. the view behaves as if the model never returns 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 does the Qt behave in such a strange way - model has way more granularity and knows way more than a style can possibly know, why does the style take precedence - after all, the model doesn't have to return the color for every single cell - only a few specific ones?

I assume it is a bug in Qt, I have opened a bug report, which is reproducible on 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 return, all the backgrounds are gone.


回答1:


I found a workaround - it still is some extra code and IMHO it should have been handled by the Qt itself, but at least there is a way to overlay the background with the default rendering, i.e. I don't need to reimplement everything the default delegate (QStyledItemDelegate) does:

    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 alpha-value of 50), it is nicely overlaid over the style's background, so that alternate-row coloring or similar stuff is still visible.

Interesting, though, I also applied the same trick to the header (in reimplemented QHeaderView::paintSection) and it didn't work - my background is visible as long as I don't call QHeaderView::paintSection - if I do, my painter->fillRect call is ignored. I'll post it as a separate question.



来源:https://stackoverflow.com/questions/30170922/how-can-i-get-the-background-color-returned-by-model-take-precedence-over-the-st

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!