Changing the row background color of a QTreeView does not work

12,735

Solution 1

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.

Solution 2

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();
}
Share:
12,735
SebastianK
Author by

SebastianK

Interested in algorithms, operations research, scheduling, C++

Updated on July 18, 2022

Comments

  • SebastianK
    SebastianK almost 2 years

    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
    SebastianK over 11 years
    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.
  • Tim Meyer
    Tim Meyer over 11 years
    @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.
  • SebastianK
    SebastianK over 11 years
    @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
    SebastianK over 11 years
    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.
  • Wojciech Cierpucha
    Wojciech Cierpucha over 11 years
    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.