11

I have a QTreeView and want different background colors for rows, depending on their content. To achieve this, I derived a class MyTreeView from QTreeView and implemented the paint method as follows:

    void MyTreeView::drawRow (QPainter* painter,
                              const QStyleOptionViewItem& option,
                              const QModelIndex& index) const
    {
      QStyleOptionViewItem newOption(option);

      if (someCondition)
      {
        newOption.palette.setColor( QPalette::Base, QColor(255, 0, 0) );
        newOption.palette.setColor( QPalette::AlternateBase, QColor(200, 0, 0) );
      }
      else
      {
        newOption.palette.setColor( QPalette::Base, QColor(0, 0, 255) );
        newOption.palette.setColor( QPalette::AlternateBase, QColor(0, 0, 200) );
      }

      QTreeView::drawRow(painter, newOption, index);
    }

Initially, I set setAlternatingRowColors(true); for the QTreeView.

My problem: Setting the color for QPalette::Base has no effect. Every second row remains white.

However, setting QPalette::AlternateBase works as expected. I tried setAutoFillBackground(true) and setAutoFillBackground(false) without any effect.

Are there any hints how to solve this problem? Thank you.


Remark: Setting the color by adapting MyModel::data(const QModelIndex&, int role) for Qt::BackgroundRole does not provide the desired result. In this case, the background color is used only for a part of the row. But I want to color the full row, including the left side with the tree navigation stuff.

Qt Version: 4.7.3


Update: For unknown reasons QPalette::Base seems to be opaque. setBrush does not change that. I found the following workaround:

    if (someCondition)
    {
        painter->fillRect(option.rect, Qt::red);
        newOption.palette.setBrush( QPalette::AlternateBase, Qt::green);
    }
    else
    {
        painter->fillRect(option.rect, Qt::orange);
        newOption.palette.setBrush( QPalette::AlternateBase, Qt:blue);
    }
SebastianK
  • 3,582
  • 3
  • 30
  • 48

3 Answers3

10

If the only problem is that the expanding/collapsing controls do not have a background like rest of the row then use Qt::BackgroundRole in ::data() of your model (as described by pnezis in their answer) and add this to your tree view class:

void MyTreeView::drawBranches(QPainter* painter,
                              const QRect& rect,
                              const QModelIndex& index) const
{
  if (some condition depending on index)
    painter->fillRect(rect, Qt::red);
  else
    painter->fillRect(rect, Qt::green);

  QTreeView::drawBranches(painter, rect, index);
}

I've tested this on Windows (Vista and 7) using Qt 4.8.0 and expanding/collapsing arrows have proper background. The problem is that those arrows are part of the view and thus cannot be handled in a model.

Community
  • 1
  • 1
  • Thank you for your answer. As you said, the drawback of this solution is that it is scattered between Model and View. But the idea with `fillRect` lead me to a reasonable workaround. – SebastianK Jan 15 '13 at 20:08
  • 1
    I agree, in this case it might be better to have coloring code only in the view - overriding other drawXXX member functions. I'm glad I could help. – Wojciech Cierpucha Jan 16 '13 at 10:44
8

Instead of subclassing QTreeView you should handle the background color through your model. Use the data() function and the Qt::BackgroundRole for changing the background color of the rows.

QVariant MyModel::data(const QModelIndex &index, int role) const
{
   if (!index.isValid())
      return QVariant();

   if (role == Qt::BackgroundRole)
   {
       if (condition1)
          return QColor(Qt::red);
       else
          return QColor(Qt::green); 
   }

   // Handle other roles

   return QVariant();
}
pnezis
  • 12,023
  • 2
  • 38
  • 38
  • 1
    I tried this, but this does not yield desired result. With this approach, the background color is not painted for the full row, but only for the tree items itself. The background of the tree navigation (on the left side of the items) is not changed. – SebastianK Jan 10 '13 at 11:22
  • @SebastianK I think this is still the right way, but the way you implement `condition1` in this example is the key. For example, you could do `if( index.sibling( index.row(), someColumnIndex ).data() == whatever ) { ... }`. You have to make sure this is not called for the case where `index.column() == someColumnIndex` as of infinite recursion of course. – Tim Meyer Jan 10 '13 at 11:46
  • @TimMeyer I tried that with `condition1` beeing always true. The background of the row was only partially red. For expanded items, the left part of the row is still white. With "left part" I mean the area with the tree navigation stuff (expanding/collapsing [+]/[-] and the line to parent) – SebastianK Jan 10 '13 at 12:00
0

https://www.linux.org.ru/forum/development/4702439

if ( const QStyleOptionViewItemV4* opt = qstyleoption_cast<const QStyleOptionViewItemV4*>(&option) )
{
        if (opt.features & QStyleOptionViewItemV4::Alternate)
            painter->fillRect(option.rect,option.palette.alternateBase());
        else
            painter->fillRect(option.rect,painter->background());
}
atz
  • 1