Changing the row background color of a QTreeView does not work
Asked Answered
S

3

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);
    }
Siderite answered 10/1, 2013 at 10:4 Comment(0)
M
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.

Merari answered 13/1, 2013 at 2:5 Comment(2)
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.Siderite
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.Merari
B
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();
}
Bihar answered 10/1, 2013 at 11:15 Comment(3)
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.Siderite
@Siderite 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.Tacheometer
@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)Siderite
W
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());
}
Wassyngton answered 17/3, 2017 at 4:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.