Qt: Анимация QPixmap - PullRequest
       37

Qt: Анимация QPixmap

0 голосов
/ 27 мая 2018

Код ответа находится здесь (https://stackoverflow.com/a/50550471/4962676):
https://github.com/eyllanesc/stackoverflow/tree/master/50550089

Ответ был более простым, чем приведенный ниже код - в приведенном выше коде используется QPropertyAnimation вместо использования для циклов с QThread, как показано ниже -это экономит тонны пространства в коде и является более эффективным.

Оригинальный вопрос ниже:

Я пишу приложение в 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 для своей анимации, заключается в том, что я как можно больше исследовал анимацию изображений, однако создать анимацию не из чего.outsidQML и приложение на C ++.

Если возможно, было бы здорово использовать QPropertyAnimation в качестве альтернативы, но я не могу анимировать размер пузырьков (кругов), в то же времяОбновление отображаемого размера.

Я извиняюсь, если кода много, я просто хотел дать как можно больше контекста (и это важно), чтобы помочь решить эту проблему.

1 Ответ

0 голосов
/ 27 мая 2018

Нет необходимости использовать 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();
}

Полный код можно найти в следующем ссылка

enter image description here

...