给QTreeWidgetItem设置第二个图标

之前的项目中需要在QTreeWidgetItem原本图标的前面额外设置一个状态图标。

基本思路是在QStyledItemDelegate::paint()中压缩text区域,扩大icon区域,然后重新绘制图标
以下是实现方式

/*!
    其他图标来自 宏 ITEMVIEW_OTHER_ICONROLE (Qt::UserRole + 11)
    仅支持第二图标,如果要支持3个及以上的图标,需要改一改
    第二图标默认放在原本图标前面,可以视情况调整icon_list中的图标顺序
*/
void DoubleIconDelegate::paint(QPainter *painter,
                               const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QList<QIcon> icon_list; //图标列表,视情况调整顺序
    icon_list.append(index.data(ITEMVIEW_OTHER_ICONROLE).value<QIcon>()); //第二图标
    icon_list.append(index.data(Qt::DecorationRole).value<QIcon>());      //原本图标

    int icon_count = icon_list.size();
    int icon_size = 16; //图标尺寸,Qt默认就是这个

    QStyleOptionViewItem opt = option;
    initStyleOption(&opt, index);

    //没有图标时也占位,并设置空位宽度
    opt.features |= QStyleOptionViewItem::HasDecoration;
    opt.decorationSize = QSize(icon_size * icon_count, icon_size); //###关键
    opt.icon = QIcon();

    const QWidget *widget = option.widget;
    QStyle *style = widget ? widget->style() : QApplication::style();

    //调用原本的绘制方法
    style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, widget);

    //以下开始绘制多图标
    painter->save();
    painter->setClipRect(opt.rect); //处理鼠标拖动压缩列宽时的遮挡效果

    QRect icon_rect = style->subElementRect(QStyle::SE_ItemViewItemDecoration, &opt, widget);
    int icon_margin = (icon_rect.width() - opt.decorationSize.width());
    icon_rect.setLeft(icon_rect.left() + icon_margin); //恢复左侧间隔

    for (int i = 0; i < icon_count; ++i)
    {
        const QIcon& icon = icon_list.at(i);
        if (icon.isNull())
        {
            continue;
        }
        
        QRect temp_icon_rect = icon_rect;
        temp_icon_rect.setLeft(icon_rect.left() + icon_size * i);
        temp_icon_rect.setWidth(icon_size);

        QIcon::Mode mode = QIcon::Normal;
        if (!(opt.state & QStyle::State_Enabled))
        {
            mode = QIcon::Disabled;
        }
        else if (opt.state & QStyle::State_Selected)
        {
            mode = QIcon::Selected;
        }
        QIcon::State state = opt.state & QStyle::State_Open ? QIcon::On : QIcon::Off;

        icon.paint(painter, temp_icon_rect, opt.decorationAlignment, mode, state);
    }
    painter->restore();
}

调用方式

    QTreeWidget* tree = new QTreeWidget(this);
    tree->setColumnCount(2);
    tree->setItemDelegate(new DoubleIconDelegate(this));

    QTreeWidgetItem* item = new QTreeWidgetItem(tree);
    item->setText(0, "Test1");
    item->setIcon(0, MakeIcon(Qt::red)); //常规设置图标方式
    item->setData(0, ITEMVIEW_OTHER_ICONROLE, MakeIcon(Qt::black));//设置第二图标方式

    item = new QTreeWidgetItem(tree);
    item->setText(0, "");
    item->setIcon(0, MakeIcon(Qt::cyan));
    item->setData(0, ITEMVIEW_OTHER_ICONROLE, MakeIcon(Qt::green));

    item = new QTreeWidgetItem(tree);
    item->setText(0, "Test3");
    item->setIcon(0, MakeIcon(Qt::yellow));
    item->setData(0, ITEMVIEW_OTHER_ICONROLE, MakeIcon(Qt::magenta));

效果如下

扩展功能
1、支持三个及以上的图标,支持放置到原有图标的前面或后面,支持放置空图标(需要设计结构体存储图标参数,而不是直接存一个QIcon)
2、支持图标响应功能,或许还要切换图标,比如类似ps的显示隐藏图层
3、支持在节点区域末尾绘制图标

posted @ 2024-07-21 16:04  HiBoX12  阅读(336)  评论(0)    收藏  举报