QTreeView项目悬停/基于当前颜色选择的背景颜色

时间:2017-03-26 22:31:39

标签: c++ qt qtstylesheets

在我的项目中,我有几个显示数据的QTreeView小部件。 QTreeView中项目的背景颜色会根据数据类型和与其他项目的关联而更改。

以下是设置背景颜色的方法:

QColor warning;
warning.setRgb(255, 86, 86);
model->itemFromIndex(index)->setData(warning, Qt::BackgroundRole);

这很有用,我还想在选择/悬停项目时使用不同的背景颜色。我选择使用样式表。

QTreeView::item:selected{background-color: #bedcf0;} //light blue
QTreeView::item:hover:selected{background-color: #94c8ea;} //darker blue
QTreeView::item:hover:!selected{background-color: #e6e6e6;} //gray

这提供了我想要的外观,但仅适用于具有白色默认背景的项目。如果某个项目具有自定义背景颜色(通过Qt::BackgroundRole设置),则这些悬停和所选颜色将完全覆盖当前背景颜色。

我希望发生的事情是,当悬停/选择基于当前背景颜色时,每个项目变暗一定量。这很难,因为QStandardItem::setProperty()不存在。

谢谢你的时间!

2 个答案:

答案 0 :(得分:3)

所以我能够自己解决这个问题。 (毫无意义的赏金,为什么我在检查它是否有效之前交出了50个代表。)

我所做的是子类QStyledItemDelegate并重新实现paint()函数。

·H

class MyStyledItemDelegate : public QStyledItemDelegate
{
    Q_OBJECT

public:
      explicit MyStyledItemDelegate(QObject *parent = 0){}

      virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
} 

在这个绘图功能中,我能够检查索引的UserRoles是否有自定义标志来决定我想要的颜色。我可以使用QStyle::State_SelectedQStyle::State_MouseOver来检查索引是被选中还是悬停。使用该信息,我能够编写逻辑来确定我想要的颜色。之后我必须手动绘制背景,图标和文字。

的.cpp

void MyStyledItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    //background
    QColor bgColor;
    int bgColorType(0);
    bgColorType = index.data(Qt::UserRole+9).toInt();//custom flag I set to determine which color i want

    //color logic
    if(bgColorType == 0)
        bgColor = QColor(Qt::transparent);//default is transparent to retain alternate row colors
    else if(bgColorType == 1)
        bgColor = qRgba(237, 106, 106, 255);//red
    else if(bgColorType == 2)
        bgColor = qRgba(241, 167, 226, 255);//pink
    //etc...

    QStyleOptionViewItem opt(option);

    if(option.state & QStyle::State_Selected)//check if item is selected
    {
        //more color logic
        if(bgColorType == 0)
            bgColor = qRgba(190, 220, 240, 255);
        else
            bgColor = qRgba(bgColor.red()-25, bgColor.green()-25, bgColor.blue()-25, 255);

        //background color won't show on selected items unless you do this
        opt.palette.setBrush(QPalette::Highlight, QBrush(bgColor));
    }

    if(option.state & QStyle::State_MouseOver)//check if item is hovered
    {
        //more color logic
        bgColor = qRgba(bgColor.red()-25, bgColor.green()-25, bgColor.blue()-25, 255);

        if(option.state & QStyle::State_Selected)//check if it is hovered AND selected
        {
            //more color logic
            if(bgColorType == 0)
            {
                bgColor = qRgba(148, 200, 234, 255);
            }

            //background color won't show on selected items unless you do this
            opt.palette.setBrush(QPalette::Highlight, QBrush(bgColor));
        }
    }


    //set the backgroundBrush to our color. This affects unselected items.
    opt.backgroundBrush = QBrush(bgColor);

    //draw the item background
    option.widget->style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter);

    //icon
    QRect iconRect = option.rect;
    iconRect.setLeft(iconRect.left()+3);//offset it a bit to the right
    //draw in icon, this can be grabbed from Qt::DecorationRole
    //altho it appears icons must be set with setIcon()
    option.widget->style()->drawItemPixmap(painter, iconRect, Qt::AlignLeft | Qt::AlignVCenter, QIcon(index.data(Qt::DecorationRole).value<QIcon>()).pixmap(16, 16));

    //text
    QRect textRect = option.rect;
    textRect.setLeft(textRect.left()+25);//offset it a bit to the right
    //draw in text, this can be grabbed from Qt::DisplayRole
    option.widget->style()->drawItemText(painter, textRect, Qt::AlignLeft | Qt::AlignVCenter, option.palette, true, index.data(Qt::DisplayRole).toString());
}

完成后,我只需将委托应用于QTreeView myTreeView->setItemDelegate(new MyStyledItemDelegate(myTreeView));

不需要样式表,后台角色更改或eventFilters。我在互联网上搜索了一个解决方案,但只发现很多人有同样的问题并且没有好的答案。这是迄今为止我提出的最简单,最通用的方法,所以我希望它可以帮助其他需要它的人:)

答案 1 :(得分:2)

所以我有一个答案。也许你可以告诉我它是否适合你和/或我们可以谈论它。

我创建了自定义QTreeViewQStandardItem,覆盖mouseMoveEvent(QMouseEvent *event)并设置了我的树的setMouseTracking(true);

我用鼠标下面的项目:static_cast<QStandardItemModel*>(model())->itemFromIndex(indexAt(event->pos()))

有了这个,我可以得到物品徘徊。然后在我的自定义项中,我有一个函数hovered()normal()。当项目悬停时,会调用悬停的方法。当鼠标移动时,它会将物品恢复正常,如果它仍在上面,则重新将其重新开始。 代码:

HoveredTreeView.cpp:

#include "HoverTreeView.h"

#include <QDebug>
#include <QMouseEvent>
#include <QStandardItemModel>

HoverTreeView::HoverTreeView(QWidget *parent)
    : QTreeView(parent)
{
    setMouseTracking(true);
}



void HoverTreeView::mouseMoveEvent(QMouseEvent *event)
{
    while (!_hoveredItems.empty())
    {
       HoverStandardItem* oldItem = _hoveredItems.pop();
       oldItem->normal();
    }
    auto *item = static_cast<QStandardItemModel*>(model())->itemFromIndex(indexAt(event->pos()));
    HoverStandardItem* realItem = static_cast<HoverStandardItem*>(item);
    if (item) {
        realItem->hovered();
        _hoveredItems.push(realItem);
    }
}

HoveredTreeView.h:

#ifndef HOVERTREEVIEW_H
#define HOVERTREEVIEW_H

#include <QStack>
#include <QTreeView>
#include "HoverStandardItem.h"

class HoverTreeView : public QTreeView
{
public:
    HoverTreeView(QWidget *parent = nullptr);

public slots:
    void    mouseMoveEvent(QMouseEvent *event);
    QStack<HoverStandardItem*> _hoveredItems;
};

#endif // HOVERTREEVIEW_H

HoveredStandardItem.cpp:

#include "HoverStandardItem.h"

HoverStandardItem::HoverStandardItem(QColor const& backgroundColor, const QString &text)
    : QStandardItem(text)
    , _backgroundColor(backgroundColor)
{
    setData(backgroundColor, Qt::BackgroundColorRole);
}

void HoverStandardItem::hovered()
{
    QColor hoveredColor(_backgroundColor);
    unsigned int darker = 20;
    hoveredColor.setRgb(hoveredColor.red() - darker, hoveredColor.green() - darker, hoveredColor.blue() - darker);
    setData(hoveredColor, Qt::BackgroundColorRole);
}

void HoverStandardItem::normal()
{
    setData(_backgroundColor, Qt::BackgroundColorRole);
}

HoveredStandardItem.h:

#ifndef HOVERSTANDARDITEM_H
#define HOVERSTANDARDITEM_H

#include <QStandardItem>

class HoverStandardItem : public QStandardItem
{
public:
    HoverStandardItem(const QColor &backgroundColor, QString const& text = "");
    void hovered();
    void normal();
private:
    QColor  _backgroundColor;
};

#endif // HOVERSTANDARDITEM_H

我在MainWindow中测试过它。这里是构造函数:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);


    QStandardItemModel *model = new QStandardItemModel(this);
    QColor warning[3] = {
    {QColor(255, 86, 86)},
        {QColor(86, 255, 86)},
        {QColor(86, 86, 255)}
    };
    for (int j = 0 ; j < 3 ; ++j) {
        QStandardItem *parentItem = model->invisibleRootItem();
        for (int i = 0; i < 4; ++i) {
            QStandardItem *item = new HoverStandardItem(warning[j], QString("item %0 %1").arg(j).arg(i));
            parentItem->appendRow(item);
            parentItem = item;
        }
    }
    ui->treeView->setModel(model);

}