繁体   English   中英

Qt:动画QPixmap

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM