我有QTreeView QStandardItemModel。我的模型可以更改为以4种不同的模式显示它的项目:
我已经制作了QStyledItemDelegate的子类来显示星星(如Star Delegate Example)
在模式2或3中,可以在选项中启用封面相册(并设置尺寸,如64 x 64像素)。
为了减少内存占用,当屏幕上显示项目时,会暂停加载封面。每次启动音频播放器时,没有后台进程正在扫描硬盘驱动器。
它工作正常,但可以改善用户体验。事实上,通过使用轮毂盖,盖子没有任何问题。使用垂直滚动条时,在500张专辑库中,向下移动时,您可以在加载* .jpeg或* .png时听到硬盘刮擦声。加载完所有封面后,滚动非常顺畅(我需要稍后处理它们)。
我已将QScrollBar子类化,并检测到MousePressEvent和MouseReleaseEvent以暂时禁用加载。
当我点击滚动条并将其连接到我的QStyledItemDelegate时,我创建了一个信号。但是,封面会在屏幕上“弹出”。
我希望使用QPropertyAnimation类(以及Animation Framework)顺利显示。遗憾的是,QStyledItemDelegate,QIcon,QStandardItem不是QObject,也不是QWidget,所以我不能使用2行或3行代码来创建这种动画。
是否存在变通方法或某种(不那么难看)的黑客攻击?
我宁愿不覆盖paintEvent来在我的QTreeView中重新创建所有内容,因为它似乎很难做到,但也许我错了。
答案 0 :(得分:1)
好吧,我没有找到QPropertyAnimation的正确方法,所以这是一个更复杂的解决方案。
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);
}
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();
}
}
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);
}