Как рисовать разные фоны с помощью QStyledItemDelegate?

Проблема:

  • У меня есть объект QTreeView и модель QStandardItemModel для просмотра виджета;
  • Для некоторых элементов я установил данные с помощью метода setData, чтобы разделить их с помощью параметра;
  • Поэтому мне нужно нарисовать другой фон pixmap для QStandardItem элементов, которые содержат значки и некоторые текстовые данные;
  • И не перерисовывать все объекты элементов, я имею в виду значок и текст. Просто смените фон.

Сначала я подумал, что:

  • Я мог бы установить таблицы стилей CSS в Qt Designer для объекта с двумя разными фоновыми изображениями, НО QStandardItem нет метода setProperty...

Пример:

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;
}
  • затем я создал свой собственный делегат, унаследованный от класса QStyledItemDelegate, и переопределил метод paint, НО я не могу просто изменить фон, потому что код QStyledItemDelegate::paint( painter, opt, index ); заменит мой drawPixmap...

Пример:

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 );
}

Так что я застрял...


person mosg    schedule 25.05.2012    source источник


Ответы (2)


Вот мой трюк:

Часть таблицы стилей Designer:

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;
}

Делегировать повторно реализованный метод paint():

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();
      }
 }

Результирующий вид QTreeView:

введите здесь описание изображения

Хорошего дня! :)

PS: не нужно перерисовывать иконки, текст, выделение...

person mosg    schedule 28.05.2012

Метод рисования делегата — это все или ничего, поэтому вы не сможете смешивать свой фон с реализацией по умолчанию.

Однако, если вы достаточно компетентны, чтобы даже подумать о написании собственного делегата, у вас не должно возникнуть проблем с реализацией того, который может рисовать ваш фон, а также значок и текст.

person cmannett85    schedule 25.05.2012
comment
Все, что я хочу, это не перерисовывать элементы строки со значками и текстами, потому что мне нужно найти правильные положения значка и текста и изменить размер значка... Я думаю, что это не лучший способ... - person mosg; 28.05.2012
comment
Судя по тому, что вы спрашиваете, у вас нет выбора. Реализация QStyledItemDelegate::paint(....) затопления по умолчанию заполняет option.rect цветом option.palette.base(), поэтому вы не можете его использовать. - person cmannett85; 28.05.2012
comment
Сказав это, QStyleOptionViewItem, переданный делегату, исходит из представления, поэтому, возможно, вы могли бы использовать CSS для предоставления нового базового цвета для QTreeView? - person cmannett85; 28.05.2012
comment
Мне нужно изменить изображения PNG, а не только цвет фона. Просто пока думаю, что может этот трюк поможет QStyleOptionViewItemV4 opt = option; if( isNewPng ) { QBrush brush = opt.backgroundBrush; brush.setTexture( QPixmap( NEW_PNG ) ); opt.backgroundBrush = brush; } QStyledItemDelegate::paint( painter, opt, index );... - person mosg; 28.05.2012