Установите QItemDelegate для определенного QTreeWidgetItem

Можно ли установить QItemDelegate на конкретный QTreeWidgetItem? Мне нужно покрасить некоторые из QTreeWidgetItem определенным цветом.

Я предполагаю, что это возможно, поскольку у нас есть QAbstractItemView::setItemDelegateForRow, но я не могу понять, как это сделать. Я не могу использовать QAbstractItemView::setItemDelegateForRow, потому что мне нужно установить собственный делегат в дочерней строке внутри QTreeWidget.

Кто-нибудь знает решение для этого?


person Jacob Krieg    schedule 03.12.2014    source источник
comment
Вы можете установить делегата для всего виджета. Затем проверьте элемент в делегате, подходит ли он для окраски или нет.   -  person Bowdzone    schedule 03.12.2014
comment
@Bowdzone Могу ли я получить доступ к QTreeWidgetItem изнутри делегата?   -  person Jacob Krieg    schedule 03.12.2014
comment
Вы помните мой последний ответ, так что можете ли вы использовать что-то if(index.parent().isValid()) или if(index.parent().row() == 1) вместо if(index.row()%2) или проверить какое-то уникальное значение элемента?   -  person Kosovan    schedule 03.12.2014
comment
@Chernobyl Привет, Чернобыль, да, я помню, но я хотел бы сделать проверку более продвинутую, чем index.row()%2, я бы проверил, например, есть ли у элемента виджета дерева определенный набор свойств (учитывая, что у меня есть пользовательский QTreeWidgetItem с дополнительным членом реализованные функции).   -  person Jacob Krieg    schedule 03.12.2014
comment
@JacobKrieg Да, можешь. Я не помню, как я это сделал, потому что я не могу получить доступ к этому моему проекту прямо сейчас. Если не забуду выложу пример через 1-2 часа   -  person Bowdzone    schedule 03.12.2014
comment
@Bowdzone Пожалуйста, сделайте это, мне очень любопытно, возможно ли это, Чернобыль сказал, что это невозможно, и, возможно, было бы хаком использовать его таким образом, но в моем случае мне действительно нужна информация :) Спасибо!   -  person Jacob Krieg    schedule 03.12.2014
comment
@Bowdzone Я тоже жду твоего ответа, мне тоже будет интересно, потому что я не знаю простого способа.   -  person Kosovan    schedule 03.12.2014


Ответы (4)


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

void custom_delegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
    const QTreeWidget* tree_widget = qobject_cast<const QTreeWidget*>(qstyleoption_cast<const QStyleOptionViewItemV3*>(&option)->widget);
    ....
}

или вы храните что-то в QModelIndex UserData как предложил Чернобыль. Однако в этом случае я бы создал enum для флагов (если это применимо в вашем случае):

enum custom_painter_flags{
    paint_default = 0,
    paint_background = 1
};

void somewhere_creating_the_items()
{
    QTreeWidgetItem* newitem = new QTreeWidgetItem(...);
    newitem->setData(0, Qt::UserRole, QVariant::fromValue<int>(custom_painter_flags::paint_background));
}

void custom_delegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
    custom_painter_flags painter_flags = static_cast<painter>(index.data(Qt::UserRole).value<int>());

    if(painter_flags & paint_background){
        ....
    }
}

К сожалению, у меня сейчас не так много времени, поэтому я быстро собрал все вместе. Не стесняйтесь редактировать, если вы найдете какие-либо ошибки.

person Bowdzone    schedule 03.12.2014
comment
Я думал о кастинге виджета, но это сломало все мои взгляды. Например: const QTreeWidget* tree_widget =... работает нормально, но после этого qDebug() << tree_widget->currentItem()->text(0); например ломает все просмотры. Перерывы с QPaintDevice: Cannot destroy paint device that is being painted Может я неправильно понял как им пользоваться? - person Kosovan; 03.12.2014
comment
Извините, у меня нет решения для этого с макушки головы - person Bowdzone; 04.12.2014
comment
Работал как шарм. Я использовал комбинацию вашего ответа и ответа @Chernobyl. К сожалению, я не могу принять оба ответа, поэтому я проголосую за него и приму ваш. Надеюсь, никто не расстроится :-s С праздником! - person Jacob Krieg; 31.12.2014

Вы не можете использовать QTreeWidgetItem в делегате напрямую (возможно, вы можете хранить список этих элементов внутри делегатов, но я думаю, что это неэффективно), потому что делегаты работают с QModelIndex и данными внутри разных ролей. Вы можете установить данные в Qt::UserRole+1 и получить к ним доступ внутри делегата. Например:

QTreeWidgetItem *cities = new QTreeWidgetItem(ui->treeWidget);
//...
cities->setData(0,Qt::UserRole+1,"chosen one");

QTreeWidgetItem *osloItem = new QTreeWidgetItem(cities);
//...

QTreeWidgetItem *berlinItem = new QTreeWidgetItem(cities);
//...
berlinItem->setData(0,Qt::UserRole+1,"chosen one");

Внутри делегата (просто пример):

    void ItemDelegatePaint::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QString txt = index.model()->data( index, Qt::DisplayRole ).toString();

    if( option.state & QStyle::State_Selected )
    {
        if(index.data(Qt::UserRole+1).toString() == "chosen one")
            painter->fillRect( option.rect,Qt::green );
        else
            painter->fillRect( option.rect, option.palette.highlight() );
    }else
    if(option.state & QStyle::State_MouseOver)
    {
        if(index.data(Qt::UserRole+1).toString() == "chosen one")
            painter->fillRect( option.rect,Qt::yellow );
        else
            painter->fillRect( option.rect, Qt::transparent );
    }
    else
    {
        QStyledItemDelegate::paint(painter,option,index);
    }
}
person Kosovan    schedule 03.12.2014
comment
Это интересно, что вы говорите, и я думаю, что это будет делать. Но разве Qt::UserRole + 1 не маленькая халтура? :-) - person Jacob Krieg; 03.12.2014
comment
@JacobKrieg Роль отображения для отображения, роль редактирования для редактирования, роль украшения для изображений и так далее, теперь вам нужна дополнительная информация, и вы используете Qt::UserRole + 1. Конечно, лучше использовать 1 или 0 вместо выбранного. Это не что-то плохое, в любом случае QTreeWidget + QTreeWidgetItem потребляет гораздо больше места, чем пользовательская модель QAbstractItemModel (Summerfield доказывает это в книгах), поэтому я думаю, что эти несколько КБ или МБ не разрушат ваш проект. - person Kosovan; 03.12.2014
comment
Спасибо! Давайте подождем, пока @Bowdzone опубликует свое решение, мне тоже любопытна его идея. - person Jacob Krieg; 03.12.2014
comment
@JacobKrieg Кто-то может подумать, что я ошибаюсь, и я хочу уточнить. С QAbstractItemModel + QTreeView мы можем добиться большего, чем с QTreeWidget + QTreeWidgetItem, и если мы будем работать очень хорошо и задача будет не очень сложной, мы можем сказать, что QAbstractItemModel + QTreeView более эффективны. Но пользовательская модель QAbstractItemModel требует много работы, очень большой работы, поэтому, как писал Саммерфилд: ... использование QStandardItemModel (или QTreeWidget в вашем случае) может сэкономить нам много работы. - person Kosovan; 03.12.2014
comment
Ты прав! Однако это тот случай, когда я вынужден работать так, поскольку код, с которым я имею дело, является устаревшим и написан людьми, которые не понимают код qt. Это больно, но пока не придет время для рефакторинга, я думаю, мне придется замарать руки. - person Jacob Krieg; 03.12.2014

Вы можете использовать qss для QTreeWidgetItem, чтобы изменить цвет или цвет фона.

person KarNal    schedule 03.12.2014
comment
Действительно, вы правы, но вы не можете изменить цвет для одних QTreeWidgetItem и не изменить его для других, используя только QSS. Вот почему я создал собственный делегат. Но я не знаю, как установить его на определенные QTreeWidgetItems или QModelIndexes в QTreeWidget. - person Jacob Krieg; 03.12.2014

Я сделал это для QTableWidget. Вы должны проверить значение всех ваших QTreeWidgetItem и установить цвет/цвет фона.

Например, для моего QTableWidget я сделал что-то подобное в цикле:

если (хороший элемент): MyQTableItem.setBackground (QtGui.QColor (255 255 255))

person KarNal    schedule 03.12.2014
comment
Да, вы правы, но вы не можете настроить цвет текста при наведении или выбранных состояниях элемента. Вот почему я выбрал для этого собственный делегат. - person Jacob Krieg; 03.12.2014