[英]Qt: Animating QPixmap
答案代码位于此处( https://stackoverflow.com/a/50550471/4962676 ):
https://github.com/eyllanesc/stackoverflow/tree/master/50550089
答案比下面的代码更简单-上面的代码使用QPropertyAnimation而不是使用带有如下QThread的for循环-这样可以节省代码中的大量空间并提高效率。
以下是原始问题:
我正在Qt中编写应用程序,但是在关闭应用程序和线程时遇到问题。
基本上,应用程序窗口是关闭的,但是该过程保留在后台并且永远不会关闭。
我的主要标头(由于包含了很多包含,因此仅包含了该类):
class ChatUI : public QWidget
{
Q_OBJECT
public:
explicit ChatUI(QWidget *parent = 0);
~ChatUI();
private:
// The UI itself
Ui::ChatUI * ui;
// Current appliation startup directory
QString applicationStartupDir = QDir::currentPath() + "/";
// Typing indicator stuff
QFrame * typingIndicator = nullptr;
QImage circleImage;
ThreadController * typingIndicatorThread = new ThreadController(false);
bool currentlyFadingTypingIndicator = false;
// The calm before the storm
bool closing = false;
void showTypingIndicator();
void hideTypingIndicator();
signals:
void WidgetClosed();
protected:
void closeEvent(QCloseEvent*);
};
我的控制器(标题):
#ifndef THREADCONTROLLER_H
#define THREADCONTROLLER_H
#include <QObject>
#include <QThread>
#include <QImage>
#include <QFrame>
#include "typingindicatorthread.h"
class ThreadController : public QObject
{
Q_OBJECT
QThread * workerThread = nullptr;
TypingIndicatorThread * worker = nullptr;
signals:
void startWork(QFrame*, QImage);
//void killThread();
public slots:
void killThread();
public:
ThreadController(bool);
};
#endif // THREADCONTROLLER_H
我的控制器(来源):
#include "threadcontroller.h"
#include <QDebug>
ThreadController::ThreadController(bool asd)
{
if (asd == true){
workerThread = new QThread();
worker = new TypingIndicatorThread;
worker->moveToThread(workerThread);
workerThread->start();
connect(this, &ThreadController::startWork, worker, &TypingIndicatorThread::startWorker);
} else {
workerThread = new QThread();
workerThread->quit();
workerThread->wait();
delete workerThread;
}
}
void ThreadController::killThread() {
emit worker->killSignal();
workerThread->quit();
workerThread->wait();
}
我的线程(标题):
#ifndef TYPINGINDICATORTHREAD_H
#define TYPINGINDICATORTHREAD_H
#include <QObject>
#include <QLabel>
#include <QPixmap>
#include <QImage>
#include <QEventLoop>
#include <QTimer>
#include <QMetaObject>
#include <QPropertyAnimation>
class TypingIndicatorThread : public QObject
{
Q_OBJECT
public:
~TypingIndicatorThread();
private:
bool kill = false;
public slots:
void startWorker(QFrame*, QImage);
void killSignal();
};
#endif // TYPINGINDICATORTHREAD_H
我的线程(源):
#include "typingindicatorthread.h"
#include <QDebug>
inline void delay(int millisecondsWait)
{
QEventLoop loop;
QTimer t;
t.connect(&t, &QTimer::timeout, &loop, &QEventLoop::quit);
t.start(millisecondsWait);
loop.exec();
}
void TypingIndicatorThread::startWorker(QFrame * typingIndicator, QImage circleImage) {
int max = 30;
int min = 5;
int waitTime = 5;
QMetaObject::invokeMethod(typingIndicator, [=]() {
QLabel * circle1 = new QLabel(typingIndicator);
circle1->setGeometry(0,0, 50, 50);
circle1->setAlignment(Qt::AlignCenter);
circle1->show();
QLabel * circle2 = new QLabel(typingIndicator);
circle2->setGeometry(40,0, 50, 50);
circle2->setAlignment(Qt::AlignCenter);
circle2->show();
QLabel * circle3 = new QLabel(typingIndicator);
circle3->setGeometry(80,0, 50, 50);
circle3->setAlignment(Qt::AlignCenter);
circle3->show();
forever {
if (kill) {
qDebug() << "Killing thread";
return;
}
// Circle1
for (int i=min; i < max; i++) {
delay(waitTime);
QPixmap circlePixmap = QPixmap::fromImage(circleImage).scaled(QSize(i, i), Qt::KeepAspectRatio, Qt::SmoothTransformation);
circle1->setPixmap(circlePixmap);
}
for (int i=max; i > min; i--) {
delay(waitTime);
QPixmap circlePixmap = QPixmap::fromImage(circleImage).scaled(QSize(i, i), Qt::KeepAspectRatio, Qt::SmoothTransformation);
circle1->setPixmap(circlePixmap);
}
// Circle2
for (int i=min; i < max; i++) {
delay(waitTime);
QPixmap circlePixmap = QPixmap::fromImage(circleImage).scaled(QSize(i, i), Qt::KeepAspectRatio, Qt::SmoothTransformation);
circle2->setPixmap(circlePixmap);
}
for (int i=max; i > min; i--) {
delay(waitTime);
QPixmap circlePixmap = QPixmap::fromImage(circleImage).scaled(QSize(i, i), Qt::KeepAspectRatio, Qt::SmoothTransformation);
circle2->setPixmap(circlePixmap);
}
// Circle3
for (int i=min; i < max; i++) {
delay(waitTime);
QPixmap circlePixmap = QPixmap::fromImage(circleImage).scaled(QSize(i, i), Qt::KeepAspectRatio, Qt::SmoothTransformation);
circle3->setPixmap(circlePixmap);
}
for (int i=max; i > min; i--) {
delay(waitTime);
QPixmap circlePixmap = QPixmap::fromImage(circleImage).scaled(QSize(i, i), Qt::KeepAspectRatio, Qt::SmoothTransformation);
circle3->setPixmap(circlePixmap);
}
}
});
}
void TypingIndicatorThread::killSignal() {
qDebug() << "oh no we are going to the shadow realm";
kill = true;
}
TypingIndicatorThread::~TypingIndicatorThread() {
emit killSignal();
}
我为我的动画使用混乱的for循环的唯一原因是因为我尽可能地研究了动画图像,但是没有什么可以在QML之外制作动画的,并且该应用程序使用c ++。
如果可能的话,最好使用QPropertyAnimation作为替代,但是我似乎无法为气泡(圆圈)的大小设置动画,同时更新其显示的大小。
如果这是很多代码,我深表歉意,我只是想提供尽可能多的上下文(并且这是相关的)来帮助解决此问题。
无需使用QThread
制作动画,因为Qt提供了QPropertyAnimation
类,并且如果您希望动画是连续的,则必须使用QSequentialAnimationGroup
对于QLabel
,必须将scaledContents
设置为true,以使QPixmap
的大小与QLabel
相同。
#include <QApplication>
#include <QFrame>
#include <QLabel>
#include <QSequentialAnimationGroup>
#include <QPropertyAnimation>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QFrame frame;
frame.resize(320, 240);
QSequentialAnimationGroup group;
group.setLoopCount(-1);
int minSize = 5;
int maxSize = 30;
int labelSize = 50;;
for(const QPoint & pos: {QPoint(0, 0), QPoint(0, 40), QPoint(0, 80)}){
QRect startVal = QRect(pos + (QPoint(labelSize, labelSize) + QPoint(-minSize, -minSize))/2 , QSize(minSize, minSize));
QRect endVal = QRect(pos + (QPoint(labelSize, labelSize) + QPoint(-maxSize, -maxSize))/2 , QSize(maxSize, maxSize));
QLabel *label = new QLabel(&frame);
label->setGeometry(startVal);
label->setPixmap(QPixmap(":/circle.png"));
label->setScaledContents(true);
label->setAlignment(Qt::AlignCenter);
QPropertyAnimation *animation = new QPropertyAnimation(label, "geometry");
animation->setStartValue(startVal);
animation->setKeyValueAt(.5, endVal);
animation->setEndValue(startVal);
animation->setDuration(1000);
group.addAnimation(animation);
}
group.start();
frame.show();
return a.exec();
}
您可以在以下链接中找到完整的代码
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.