Можно ли анимировать непрозрачность QIcon в QStyledItemDelegate?

контекст

у меня есть QTreeView с QStandardItemModel. Моя модель может быть изменена для отображения ее элементов в 4 различных режимах:

  1. Уровень 0: Исполнитель \ Уровень 1: Альбом \ Уровень 2: Треки
  2. Уровень 0: Исполнитель — Альбом \ Уровень 1: Треки
  3. Уровень 0: Альбомы \ Уровень 1: Треки
  4. Уровень 0: Год \ Уровень 1: Исполнитель — Альбом \ Уровень 2: Треки

Я сделал подкласс QStyledItemDelegate для отображения звезд (например, Пример звездного делегата)

В режиме 2 или 3 можно включить обложку альбома в настройках (и установить размер, например, 64 х 64 пикселя).

Чтобы уменьшить объем памяти, обложки лениво загружаются, когда элементы отображаются на экране. Ни один фоновый процесс не сканирует жесткий диск каждый раз, когда вы запускаете аудиоплеер.

Это работает нормально, но пользовательский опыт может быть улучшен. На самом деле, используя колесную мышку, чехлы загружаются без проблем. При использовании вертикальной полосы прокрутки в библиотеке 500 альбомов и ее перемещении вниз вы можете услышать царапины на жестком диске при загрузке * .jpeg или * .png. После того, как все обложки загружены, прокрутка становится совершенно плавной (мне нужно избавиться от них позже).

Вот что я сделал до сих пор:

Я подкласс QScrollBar и обнаружил MousePressEvent а также MouseReleaseEvent временно отключить загрузку.

Я создал сигнал, когда кто-то нажимает на полосу прокрутки, и подключил его к моему QStyledItemDelegate. Тем не менее, обложки «появляются» на экране.

Что я ищу:

Я хотел бы отображать плавно, с QPropertyAnimation класс (и Анимационные рамки). К сожалению, QStyledItemDelegate, QIcon, QStandardItem не являются ни QObject, ни QWidget, поэтому я не могу использовать 2 или 3 строки кода для создания этого вида анимации.

Есть ли обходной путь, или какой-то (не такой уродливый) взлом?

Я бы предпочел не переопределять paintEvent, чтобы воссоздать все с нуля в моем QTreeView, потому что это кажется довольно сложным, но, возможно, я ошибаюсь.

0

Решение

Ну, я не нашел правильного способа с 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);
}
1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]