是否可以在QStyledItemDelegate中设置QIcon的不透明度?

时间:2014-01-24 11:32:40

标签: c++ qt qt5 user-experience

上下文

我有QTreeView QStandardItemModel。我的模型可以更改为以4种不同的模式显示它的项目:

  1. 等级0:艺术家\等级1:专辑\等级2:曲目
  2. 等级0:艺术家 - 专辑\等级1:曲目
  3. 等级0:专辑\等级1:曲目
  4. 等级0:年级\等级1:艺术家 - 专辑\等级2:曲目
  5. 我已经制作了QStyledItemDelegate的子类来显示星星(如Star Delegate Example

    在模式2或3中,可以在选项中启用封面相册(并设置尺寸,如64 x 64像素)。

    为了减少内存占用,当屏幕上显示项目时,会暂停加载封面。每次启动音频播放器时,没有后台进程正在扫描硬盘驱动器。

    它工作正常,但可以改善用户体验。事实上,通过使用轮毂盖,盖子没有任何问题。使用垂直滚动条时,在500张专辑库中,向下移动时,您可以在加载* .jpeg或* .png时听到硬盘刮擦声。加载完所有封面后,滚动非常顺畅(我需要稍后处理它们)。

    这是我到目前为止所做的:

    我已将QScrollBar子类化,并检测到MousePressEventMouseReleaseEvent以暂时禁用加载。

    当我点击滚动条并将其连接到我的QStyledItemDelegate时,我创建了一个信号。但是,封面会在屏幕上“弹出”。

    我在找什么:

    我希望使用QPropertyAnimation类(以及Animation Framework)顺利显示。遗憾的是,QStyledItemDelegate,QIcon,QStandardItem不是QObject,也不是QWidget,所以我不能使用2行或3行代码来创建这种动画。

    是否存在变通方法或某种(不那么难看)的黑客攻击?

    我宁愿不覆盖paintEvent来在我的QTreeView中重新创建所有内容,因为它似乎很难做到,但也许我错了。

1 个答案:

答案 0 :(得分:1)

好吧,我没有找到QPropertyAnimation的正确方法,所以这是一个更复杂的解决方案。

类LibraryScrollBar

void LibraryScrollBar::mouseMoveEvent(QMouseEvent *e)
{
    if (_hasNotEmittedYet) {
        qDebug() << "hide covers when moving";
        emit displayItemDelegate(false);
        _hasNotEmittedYet = false;
    }
    QScrollBar::mouseMoveEvent(e);
}

void LibraryScrollBar::mouseReleaseEvent(QMouseEvent *e)
{
    if (!_hasNotEmittedYet) {
        qDebug() << "show covers when stopped moving";
        emit displayItemDelegate(true);
        _hasNotEmittedYet = true;
    }
    QScrollBar::mouseReleaseEvent(e);
}

在类LibraryTreeView

void LibraryTreeView::init(LibrarySqlModel *sql)
{
    /// some code before
    LibraryScrollBar *vScrollBar = new LibraryScrollBar(this);
    this->setVerticalScrollBar(vScrollBar);
    connect(vScrollBar, &LibraryScrollBar::displayItemDelegate, [=](bool b) {
        _itemDelegate->displayIcon(b);
        b ? _timer->start() : _timer->stop();
    });
    connect(_timer, &QTimer::timeout, this, &LibraryTreeView::repaintIcons);
}

void LibraryTreeView::repaintIcons()
{
    static qreal r = 0;
    if (_timer->isActive()) {
        r += 0.01;
        _itemDelegate->setIconOpacity(r);
        if (r >= 1) {
            _timer->stop();
            r = 0;
        }
        this->viewport()->repaint();
    }
}

在类LibraryItemDelegate

void LibraryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    painter->save();
    painter->setFont(Settings::getInstance()->font(Settings::LIBRARY));
    QStandardItem *item = _libraryModel.data()->itemFromIndex(_proxy.data()->mapToSource(index));
    QStyleOptionViewItem o = option;
    initStyleOption(&o, index);

    // Removes the dotted rectangle to the focused item
    o.state &= ~QStyle::State_HasFocus;
    int type = item->data(LibraryTreeView::Type).toInt();
    switch (type) {
    case LibraryTreeView::Album:
        this->drawAlbum(painter, o, item);
        break;
    /// etc
    }
    painter->restore();
}

/** Albums have covers usually. */
void LibraryItemDelegate::drawAlbum(QPainter *painter, QStyleOptionViewItem &option, QStandardItem *item) const
{
    static QImageReader imageReader;
    static int coverSize = Settings::getInstance()->coverSize();
    QString file = item->data(LibraryTreeView::DataCoverPath).toString();
    // Display a light selection rectangle when one is moving the cursor
    if (option.state & QStyle::State_MouseOver && ~option.state & QStyle::State_Selected) {
        painter->save();
        painter->setPen(option.palette.highlight().color());
        painter->setBrush(option.palette.highlight().color().lighter(175));
        painter->drawRect(option.rect.adjusted(0, 0, -1, -1));
        painter->restore();
    } else if (option.state & QStyle::State_Selected) {
        // Display a not so light rectangle when one has chosen an item. It's darker than the mouse over
        painter->save();
        painter->setPen(option.palette.highlight().color());
        painter->setBrush(option.palette.highlight().color().lighter(160));
        painter->drawRect(option.rect.adjusted(0, 0, -1, -1));
        painter->restore();
    }
    if (_showCovers) {
        /// XXX: extract this elsewhere
        // Qt::UserRole + 20 == false => pixmap not loaded ; == true => pixmap loaded
        if (item->data(Qt::UserRole + 20).toBool() == false && !file.isEmpty()) {
            FileHelper fh(file);
            QFileInfo f(file);
            qDebug() << "loading cover from harddrive";
            // If it's an inner cover, load it
            if (FileHelper::suffixes().contains(f.suffix())) {
                std::unique_ptr<Cover> cover(fh.extractCover());
                if (cover) {
                    QPixmap p;
                    p.loadFromData(cover->byteArray(), cover->format());
                    p = p.scaled(coverSize, coverSize);
                    item->setIcon(p);
                    item->setData(true, Qt::UserRole + 20);
                }
            } else {
                imageReader.setFileName(QDir::fromNativeSeparators(file));
                imageReader.setScaledSize(QSize(coverSize, coverSize));
                item->setIcon(QPixmap::fromImage(imageReader.read()));
                item->setData(true, Qt::UserRole + 20);
            }
        }
    }
    bool b = item->data(Qt::UserRole + 20).toBool();
    if (_showCovers && b) {
        QPixmap p = option.icon.pixmap(QSize(coverSize, coverSize));
        QRect cover(option.rect.x() + 1, option.rect.y() + 1, coverSize, coverSize);
        if (_animateIcons) {
            painter->save();
            painter->setOpacity(_iconOpacity);
            painter->drawPixmap(cover, p);
            painter->restore();
        } else {
            painter->drawPixmap(cover, p);
        }
    }
    // It's possible to have missing covers in your library, so we need to keep alignment.
    QPoint topLeft(option.rect.x() + coverSize + 5, option.rect.y());
    QFontMetrics fmf(Settings::getInstance()->font(Settings::LIBRARY));
    QRect rectText(topLeft, option.rect.bottomRight());
    option.textElideMode = Qt::ElideRight;
    QString s = fmf.elidedText(option.text, Qt::ElideRight, rectText.width());
    painter->drawText(rectText, Qt::AlignVCenter, s);
}