HowTo draw different backgrounds with QStyledItemDelegate?

9.4k views Asked by At

Problem:

  • I have QTreeView object, and a QStandardItemModel as model to view widget;
  • For some item's I have set data with setData method to split them with a parameter;
  • So I need to draw different background pixmap for QStandardItem items, which are with icon's and some text data;
  • And don't want to redraw all the items objects, I mean icon and text. Just change background.

First, I was thinking that:

  • I could set CSS stylesheets in Qt Designer for the object with 2 different background pictures, BUT QStandardItem doesn't have setProperty method...

Example:

QTreeView#treeView::item[ROLE="AAA"],
QTreeView#treeView::branch[ROLE="AAA"]
{
    height: 25px;
    border: none;
    color: #564f5b;
    background-image: url(:/backgrounds/images/row1.png);
    background-position: top left;
}

QTreeView#treeView::item[ROLE="BBB"],
QTreeView#treeView::branch[ROLE="BBB"]
{
    height: 25px;
    border: none;
    color: #564f5b;
    background-image: url(:/backgrounds/images/row2.png);
    background-position: top left;
}
  • then I created my own delegate, inherited from QStyledItemDelegate class, and reimplement paint method, BUT I can't just change background, because QStyledItemDelegate::paint( painter, opt, index ); code will overdraw my drawPixmap...

Example:

QStyleOptionViewItemV4 opt = option; // Для обхода QTBUG-4310
opt.state &= ~QStyle::State_HasFocus; // Чтобы не рисовался прямоугольник фокуса 

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

// HERE I WANT TO CHANGE BACKGROUND (DEFAULT IS ALREADY SET IN DESIGNER WITH ABOVE CODE)
if( index.data( SORT_ROLE ).toBool() )
{
    const QPixmap pixmap( ":/backgrounds/images/backgrounds/contractor_row__high_priority.png" );
    painter->drawPixmap( option.rect, pixmap, pixmap.rect() );

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

So I'm stuck...

2

There are 2 answers

0
mosg On BEST ANSWER

Here is my trick:

The Designer's stylesheet part:

QTreeView#treeView
{
    border: none;
    background-color:#f0f0f1;
}   

QTreeView#treeView::item,
QTreeView#treeView::branch
{
    height: 25px;
    border: none;
    color: #564f5b;
}

QTreeView#treeView::item:selected,
QTreeView#treeView::branch:selected
{
    border-bottom: none;
    color: #ffffff;    
    background-image: url(:/backgrounds/images/backgrounds/kontragents_row_selection.png);
    background-position: top left;  

}

QTreeView#treeView::item:selected:!active,
QTreeView#treeView::branch:selected:!active
{
    color: #ffffff;
}

Delegate reimplemented paint() method:

void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
 {
      QStyleOptionViewItemV4 opt = option; // Для обхода QTBUG-4310
      opt.state &= ~QStyle::State_HasFocus; // Чтобы не рисовался прямоугольник фокуса

      QBrush brush = opt.backgroundBrush;
      brush.setTexture( QPixmap( index.data( SORT_ROLE ).toBool()
           ? BACKGROUND_HIGH_PRIORITY
           : BACKGROUND_STANDARD ) );

      // FILL BACKGROUND     
      painter->save();
      painter->fillRect( opt.rect, brush );
      painter->restore();

      // DRAW ICON & TEXT
      QStyledItemDelegate::paint( painter, opt, index );

      // IF ( CHILD ) THEN PAINT OVER ONLY! BRANCH RECT
      bool isIndexParent = !index.parent().isValid();
      if( !isIndexParent )
      {
           QRect rect( 0, opt.rect.y(), 20, opt.rect.height() );

           if( opt.state & QStyle::State_Selected )
           {
                brush.setTexture( QPixmap( BACKGROUND_SELECTED ) );
           }

           painter->save();
           painter->fillRect( rect, brush );
           painter->restore();
      }
 }

Resulting QTreeView view:

enter image description here

Have a nice day! :)

PS: no need redrawing icons, text, selection...

4
cmannett85 On

The delegate's paint method is all or nothing, so you won't be able to mix your background with the default implementation's.

However, if you're competent enough to even consider writing a custom delegate, you should have no problem implementing one that can draw your background plus icon and text.