PDA

View Full Version : QMovie from inside a custom item delegate



Crazy_Hopper
7th May 2008, 03:52
Hi,

I wonder if it's possible to embed an animated image (preferably scaled) into a QTreeView cell.

So far I have achieved it by creating QMovie in the model and connecting its frameChanged() signal to model's dataChanged() signal. It turned out to be really CPU heavy as compared to QLabel with movie set into it.

Could you please suggest a better way to do it?

Gopala Krishna
7th May 2008, 07:31
Hi,

I wonder if it's possible to embed an animated image (preferably scaled) into a QTreeView cell.

So far I have achieved it by creating QMovie in the model and connecting its frameChanged() signal to model's dataChanged() signal. It turned out to be really CPU heavy as compared to QLabel with movie set into it.

Could you please suggest a better way to do it?

Hmm interesting use case...
As far as i know, the model's data changed signal is supposed to be emitted only if the data changes. In your case not each frame can be regarded as data. Model should only set the right QMovie for the delagate and that delegate should handle its painting as and when requested by the QMovie.

You can use the techniques adopted by QLabel for playing the movie, which is nothing but painting the pixmaps as and when requested by QMovie. I am pasting here for quick reference.


void QLabel::setMovie(QMovie *movie)
{
Q_D(QLabel);
d->clearContents();

if (!movie)
return;

d->movie = movie;
connect(movie, SIGNAL(resized(QSize)), this, SLOT(_q_movieResized(QSize)));
connect(movie, SIGNAL(updated(QRect)), this, SLOT(_q_movieUpdated(QRect)));

// Assume that if the movie is running,
// resize/update signals will come soon enough
if (movie->state() != QMovie::Running)
d->updateLabel();
}

void QLabelPrivate::_q_movieUpdated(const QRect& rect)
{
Q_Q(QLabel);
if (movie && movie->isValid()) {
QRect r;
if (scaledcontents) {
QRect cr = q->contentsRect();
QRect pixmapRect(cr.topLeft(), movie->currentPixmap().size());
if (pixmapRect.isEmpty())
return;
r.setRect(cr.left(), cr.top(),
(rect.width() * cr.width()) / pixmapRect.width(),
(rect.height() * cr.height()) / pixmapRect.height());
} else {
r = q->style()->itemPixmapRect(q->contentsRect(), align, movie->currentPixmap());
r.translate(rect.x(), rect.y());
r.setWidth(qMin(r.width(), rect.width()));
r.setHeight(qMin(r.height(), rect.height()));
}
q->update(r);
}
}

void QLabelPrivate::_q_movieResized(const QSize& size)
{
Q_Q(QLabel);
valid_hints = false;
_q_movieUpdated(QRect(QPoint(0,0), size));
q->updateGeometry();
}
void QLabel::paintEvent(QPaintEvent *)
{
Q_D(QLabel);
QStyle *style = QWidget::style();
QPainter painter(this);
drawFrame(&painter);
QRect cr = contentsRect();
cr.adjust(d->margin, d->margin, -d->margin, -d->margin);
int align = QStyle::visualAlignment(layoutDirection(), QFlag(d->align));

#ifndef QT_NO_MOVIE
if (d->movie) {
if (d->scaledcontents)
style->drawItemPixmap(&painter, cr, align, d->movie->currentPixmap().scaled(cr.size()));
else
style->drawItemPixmap(&painter, cr, align, d->movie->currentPixmap());
}

... snip...

Crazy_Hopper
7th May 2008, 14:57
Hmm interesting use case...
As far as i know, the model's data changed signal is supposed to be emitted only if the data changes. In your case not each frame can be regarded as data. Model should only set the right QMovie for the delagate and that delegate should handle its painting as and when requested by the QMovie.

You can use the techniques adopted by QLabel for playing the movie, which is nothing but painting the pixmaps as and when requested by QMovie.

With QLabel, QMovie generates a signal, it's processed and update() is called on QLabel which generates the paintEvent() for QLabel. It seems I do pretty much the same here. Besides, I guess there is no other way to call delegate's paint() but calling model's dataChanged().

What I need is a code excerpt for delegate's paint() that shows a movie.

Gopala Krishna
7th May 2008, 16:18
With QLabel, QMovie generates a signal, it's processed and update() is called on QLabel which generates the paintEvent() for QLabel. It seems I do pretty much the same here. Besides, I guess there is no other way to call delegate's paint() but calling model's dataChanged().

What I need is a code excerpt for delegate's paint() that shows a movie.

Oh ok now i realize.
How about updating the movie delegate from the QTreeView manually ? May be you can somehow find the rect corresponding to the delegate and keep issuing update(QRect) for the QTreeView on signal from the QMovie.
What my idea is to avoid dataChanged signal in such a rapid rate since that results in quite expensive operations in the internal structures of InterView.