QTableView row styling

klasyc picture klasyc · Oct 6, 2014 · Viewed 8.2k times · Source

I have got a QTableView component displaying several types of data in the rows. What I need is to display each type of row by different color. My stylesheet looks like this:

RecordSheet::item {
        border: 0px;
        color: black;
        padding: 1px 0px 0px 3px;
}
RecordSheet::item:selected, RecordSheet::item:selected:!active {
        background-color: #e8b417;
        color: black;
}

I have two ideas how to achieve this:

  1. Use data() method in the model and respond to the Qt::BackgroundColorRole. Unfortunately when I do it, the background color is ignored until I remove the border: 0px; from the stylesheet and when I remove the border, the styleshhet's padding is ignored. Strange...

  2. Setup a CSS/QSS class for each type of row and set their colors in the stylesheet. Then use the model to assign a proper class for each type of row. So the stylesheet would look like this:

    RecordSheet::item {
        border: 0px;
        color: black;
        padding: 1px 0px 0px 3px;
    }
    RecordSheet::item[class=green_row] {
            background-color: green;
    }
    RecordSheet::item[class=red_row] {
            background-color: red;
    }
    

    I like this approach more because it separates content from the appearance, but I don't have any idea how to do it. Maybe using an ItemDelegate?

Please, does anybody know a nice and simple solution?

Kind regards and many thanks.

Jan

Answer

Kosovan picture Kosovan · Nov 30, 2014

You don't need stylesheet to do this, styleshhet is not so powerful to do all things that developer wants. Use more powerful thing - delegate. I will show you main idea and working example. Header:

#ifndef ITEMDELEGATEPAINT_H
#define ITEMDELEGATEPAINT_H

#include <QStyledItemDelegate>

class ItemDelegatePaint : public QStyledItemDelegate
{
    Q_OBJECT
public:
    explicit ItemDelegatePaint(QObject *parent = 0);
    ItemDelegatePaint(const QString &txt, QObject *parent = 0);


protected:
    void paint( QPainter *painter,
                const QStyleOptionViewItem &option,
                const QModelIndex &index ) const;
    QSize sizeHint( const QStyleOptionViewItem &option,
                    const QModelIndex &index ) const;
    QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    void setEditorData(QWidget * editor, const QModelIndex & index) const;
    void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const;
    void updateEditorGeometry(QWidget * editor, const QStyleOptionViewItem & option, const QModelIndex & index) const;

signals:

public slots:

};

#endif // ITEMDELEGATEPAINT_H

There are many methods here but I will show you only paint, because it is the most important thing for you. Description about another methods you can find in web

cpp:

void ItemDelegatePaint::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QString txt = index.model()->data( index, Qt::DisplayRole ).toString();

    if(index.row() == 0)//green row
        painter->fillRect(option.rect,QColor(0,255,0));
    else
        if(index.row() == 1)//blue row
            painter->fillRect(option.rect,QColor(0,0,255));
    else
        if(index.row() == 2)//red row
            painter->fillRect(option.rect,QColor(255,0,0));
    //and so on

    if( option.state & QStyle::State_Selected )//we need this to show selection
    {
        painter->fillRect( option.rect, option.palette.highlight() );
    }


    QStyledItemDelegate::paint(painter,option,index);//standard processing
}

Usage:

ui->tableView->setItemDelegate(new ItemDelegatePaint);

Result:

enter image description here