GIF animation in Qt
I don't use GIF animation with QGraphicsView
or QGraphicsScene
, I use it only in QDialog
, but I think it's the same stuff, so here is my code:
QMovie *movie = new QMovie(":/images/other/images/16x16/loading.gif");
QLabel *processLabel = new QLabel(this);
processLabel->setMovie(movie);
movie->start();
My loading.gif
I took from this link.
PS: also check the examples from Qt SDK. They are really can help!
Showing a .gif animation in QLabel
you can add a Layout to the label, and then add another Label with the text to that...
self.status_txt = QtGui.QLabel()
movie = QtGui.QMovie("etc/loading.gif")
self.status_txt.setMovie(movie)
movie.start()
self.status_txt.setLayout(QtGui.QHBoxLayout())
self.status_txt.layout().addWidget(QLabel('Loading...'))
edit:
it's possible if you use your own version of a QLabel and a QPainter to paint the text yourself:
from PyQt4.QtCore import QSize
from PyQt4.QtGui import QApplication, QLabel, QMovie, QPainter, QFontMetrics
class QTextMovieLabel(QLabel):
def __init__(self, text, fileName):
QLabel.__init__(self)
self._text = text
m = QMovie(fileName)
m.start()
self.setMovie(m)
def setMovie(self, movie):
QLabel.setMovie(self, movie)
s=movie.currentImage().size()
self._movieWidth = s.width()
self._movieHeight = s.height()
def paintEvent(self, evt):
QLabel.paintEvent(self, evt)
p = QPainter(self)
p.setFont(self.font())
x = self._movieWidth + 6
y = (self.height() + p.fontMetrics().xHeight()) / 2
p.drawText(x, y, self._text)
p.end()
def sizeHint(self):
fm = QFontMetrics(self.font())
return QSize(self._movieWidth + 6 + fm.width(self._text),
self._movieHeight)
def setText(self, text):
self._text = text
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
l = QTextMovieLabel('Loading...', 'loading.gif')
l.show()
app.exec_()
Switch between GIF animations with QMovie and signals/slots in Qt
First, for removing the error, just declare your QMovie
in your header file (which I believe is the one named abv.h
).
In your .h :
private :
QMovie* _movie;
In your .cpp :
abv::abv(QWidget *parent) :
QDialog(parent, Qt::FramelessWindowHint),
ui(new Ui::abv)
{
QString project = projectGifs();
_movie = new QMovie(project); // this line changes
...
Now, you connect the signal frameChanged(int)
to the constructor abv::abv()
. It won't work because :
- mainly, your constructor can't be a slot ;
- the signature is not the same (the slot must take an
int
as a parameter, like the signal does)
Moreover, why are you doing it like this? The signal frameChanged(int) is emitted each time a new image is sent to the user(!). You are currently telling your program to launch a new GIF everytime a frame changes. Your code won't work this way.
If I understand well, you just have to connect the signal QMovie::finished() to a slot where you will call another GIF. Your QLabel
will have to be a class variable as well. Something like this :
In your .h :
private
QMovie* _movie;
QLabel* _label;
public slots :
void startNewAnimation();
And in your .cpp :
abv::abv(QWidget *parent) :
QDialog(parent, Qt::FramelessWindowHint),
ui(new Ui::abv)
{
QString project = projectGifs(); //projectGifs() is a function stated in my header that sends over a randomly selected gif
_movie = new QMovie(project);
if (!_movie->isValid())
cout << "The gif is not valid!!!";
_label = new QLabel(this);
QObject::connect(
_movie, SIGNAL(finished()),
this, SLOT(startNewAnimation())); //stop animation and get new animation
_label->setMovie(_movie);
_movie->start();
}
void abv::startNewAnimation()
{
// here you need to call your new GIF
// and then you just put it in your label
// you can also disconnect the signal finished() if you want
QString newGIF = projectGifs();
_movie = new QMovie(newGIF);
_label->setMovie(_movie);
}
Animated GIF ins't displayed with Qt on Windows
First, sorry for my bad english. I managed to solve this in 3 steps. I don't know whether it is correct way to do it but it works!
- Create a folder name 'imageformats' in the same directory of your application.
- Copy qgif.dll from your qt plugins directory and paste to the folder.
- Put your gif files in the same folder.
Note:
But make sure to set your current path of QMovie's object correctly.
For e.g :
eye_right = new QMovie(QDir::currentPath()+"/imageformats/eye_right.gif");
gif image in QLabel
The problem is that QLabel
has window background by default. You're trying to remove it by do it incorrectly:
FramelessWindowHint
doesn't make sense here, since it's only used for top level widgets, and a widget added to scene is technically hidden and doesn't have system window frame. This line should be removed.
setMask
does exactly what you describe it does. Since QPixmap
is not animated, its mask is the alpha mask of the first frame of animation. And you permanently apply this mask to the label. It's not surpising that it works, but obviously it's not what you want. This line should also be removed.
setGeometry
line is incorrect. It prevents picture from being visible for me. Label has good size by default and there is no need for setGeometry
. If you want to scale or move the item on the scene, you can do it after addWidget
as for any other QGraphicsItem
. E.g. addWidget(lbl)->setPos(10, 10)
.
The magic bullet you need is WA_NoSystemBackground
. It disables background painting for QLabel
completely. So, the full code would be:
QLabel *lbl = new QLabel;
QMovie *mv = new QMovie("c:/tmp/sun.gif");
mv->start();
lbl->setAttribute(Qt::WA_NoSystemBackground);
lbl->setMovie(mv);
scene.addWidget(lbl);
It works fine for me. However I consider it over-complicated. You should not use proxy widgets in scene unless necessary. You can easily add a movie using QMovie
and QGraphicsPixmapItem
and switching pixmaps as movie frames change. I wrote a convenient class for this:
Header:
class GraphicsMovieItem : public QObject, public QGraphicsPixmapItem {
Q_OBJECT
public:
GraphicsMovieItem(QGraphicsItem* parent = 0);
void setMovie(QMovie* movie);
private:
QMovie* m_movie;
private slots:
void frameChanged();
};
Source:
GraphicsMovieItem::GraphicsMovieItem(QGraphicsItem *parent)
: QGraphicsPixmapItem(parent), m_movie(0) {
}
void GraphicsMovieItem::setMovie(QMovie *movie) {
if (m_movie) {
disconnect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frameChanged()));
}
m_movie = movie;
if (m_movie) {
connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frameChanged()));
}
frameChanged();
}
void GraphicsMovieItem::frameChanged() {
if (!m_movie) { return; }
setPixmap(m_movie->currentPixmap());
}
Usage:
QMovie *mv = new QMovie("c:/tmp/sun.gif");
GraphicsMovieItem* item = new GraphicsMovieItem();
item->setMovie(mv);
scene.addItem(item);
Related Topics
Best Method for Storing This Pointer for Use in Wndproc
How to Generate Assembly Code with Clang in Intel Syntax
Converting Data from Glreadpixels() to Opencv::Mat
What Is the Meaning of Clang's -Wweak-Vtables
Handling Header Files Dependencies with Cmake
Can Openssl on Windows Use the System Certificate Store
Can't Overload Operator<< as Member Function
How to Change the Variable to Which a C++ Reference Refers
Why Is Std::Fill(0) Slower Than Std::Fill(1)
Difference Between Long and Int Data Types
C++ - Arguments for Exceptions Over Return Codes
Get the Status of a Std::Future
Could I Ever Want to Access the Address Zero
Accessing Protected Members of Superclass in C++ with Templates