在QTreeView中为不同的复选框设置不同的图像

时间:2017-10-17 12:26:22

标签: css qt qtreeview

我将QTreeView子类化,我有两列有复选框。我想设置两个不同的图像:一个用于第一列,另一个用于第二列。我知道我可以用样式更改样式表中的图像:

QTreeView::indicator:checked{
    image: url(:/checked);
}

QTreeView::indicator:unchecked{
    image: url(:/unchecked);
}

但它会更改树视图中的所有复选框。有没有办法用样式表来做,或者我需要使用委托吗?

1 个答案:

答案 0 :(得分:7)

简短回答:样式表不能这样做(据我所知)。它们在Qt中是一个非常不成熟的特性,它们似乎也没有发展。

你能做什么:

样式表

您无法为列或项目分配属性,也无法通过索引访问列。

但是你可以使用一些伪状态选择器,如:first:middle:last

QTreeView::indicator:first:checked{
    background: red;
}
QTreeView::indicator:middle:checked{
    background: blue;
}
QTreeView::indicator:unchecked{
    background: lightgray;
}

为简单起见,我使用的是颜色而不是图像。 但请注意,这些伪状态是实际当前可见的状态,因此如果允许用户对列重新排序,则列的样式可能会更改。例如,如果用户拖动其中一个:middle列并将其放在最后,那么该框将不再是蓝色。

DecorationRole

您可以使用Qt::DecorationRole伪造它。

为此,您必须通过继承mousePressEvent或安装event filter来接收QTreeView。然后,当用户点击图标区域时,您可以更改图标(通过Qt::DecorationRole + emit dataChanged())。

当然,这不适用于键盘。

自定义ItemDelegate

子类QStyledItemDelegate并覆盖paint(),正如您所建议的那样。

自定义样式

如果要创建风格很大的应用程序,则可能迟早要创建自定义样式。样式表只是不支持某些功能。

为此,子类QProxyStyle,覆盖drawPrimitive并在传递QStyle::PE_IndicatorViewItemCheck时处理绘图。您还会收到一个QStyleOptionViewItem,其中包含一些有用的属性,例如checkStatefeatures(如果有复选框,则包含QStyleOptionViewItem::HasCheckIndicator),当然还有index这样您就可以确定要绘制的复选框类型。

编辑:附录

使用自定义QStyledItemDelegate

的示例
void MyItemDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const
{
    QStyledItemDelegate::paint(painter, option, index);
    QStyleOptionViewItem opt = option;
    initStyleOption(&opt, index);

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

    QRect checkRect = style->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &opt, widget);
    drawCheckBox(painter, checkRect, opt.checkState, index);
}

void MyItemDelegate::drawCheckBox(QPainter * painter, const QRect & checkRect, Qt::CheckState checkState, const QModelIndex & index) const
{
    if (checkState == Qt::Checked)
    {
        switch (index.column())
        {
            case 0:
                painter->fillRect(checkRect, Qt::red);
                break;
            default:
                painter->fillRect(checkRect, Qt::blue);
        }
    }
    else
    {
        painter->fillRect(checkRect, Qt::lightGray);
    }
}

这个例子快速而简单。只需在QStyledItemDelegate绘制的复选框上绘制。但是要求你填满整个盒子,否则原件将可见。

您可以尝试使用QStyledItemDelegate绘制除复选框之外的任何内容,然后绘制复选框,但如果您不想花太多时间在它上面,那会有点困难并会留下一些小的绘图工件

使用自定义QProxyStyle的示例

void MyStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption * opt, QPainter * p, const QWidget * w) const
{
    if (pe == QStyle::PE_IndicatorViewItemCheck)
    {
        const QStyleOptionViewItem * o = static_cast<const QStyleOptionViewItem *>(opt);
        drawCheckBox(p, opt->rect, o->checkState, o->index);
        return;
    }
    QProxyStyle::drawPrimitive(pe, opt, p, w);
}

drawCheckBox()功能与第一个示例中的功能相同。 正如您所看到的,这种方式更简单,更清洁并且没有任何缺点。您可以全局应用样式,也可以仅应用于单个窗口小部件。