Qt

QPropertyAnimation 예제 Circle형태의 PrograssBar

Qt쓰는 사람 2018. 11. 2. 16:47
//.h

//////////////////////////////////////////////////////////////////////////////
// Date of creation: 04.07.2013
// Creator: Alexander Egorov aka mofr
// Modifier : sp.Park 2018.10.30
// Authors: mofr
//////////////////////////////////////////////////////////////////////////////

#pragma once

#include <QWidget>
#include <QPropertyAnimation>

class ProgressCircle : public QWidget
{
private:
    Q_OBJECT
    Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged)
    Q_PROPERTY(int maximum READ maximum WRITE setMaximum NOTIFY maximumChanged)
    Q_PROPERTY(qreal innerRadius READ innerRadius WRITE setInnerRadius)
    Q_PROPERTY(qreal outerRadius READ outerRadius WRITE setOuterRadius)
    Q_PROPERTY(QColor color READ color WRITE setColor)

    Q_PROPERTY(qreal infiniteAnimationValue READ infiniteAnimationValue WRITE setInfiniteAnimationValue)
    Q_PROPERTY(int visibleValue READ visibleValue WRITE setVisibleValue)

    struct privateStruct;
public:
    explicit ProgressCircle(QWidget *parent = nullptr);
    virtual ~ProgressCircle();

    int value() const;

    /**
     * @brief maximum
     * If maximum <= 0, widget shows infinite process;
     * @return
     */
    int maximum() const;

    /**
     * @brief innerRadius = [0.0 .. 1.0]
     * @return
     */
    qreal innerRadius() const;

    /**
     * @brief outerRadius = [0.0 .. 1.0]
     * @return
     */
    qreal outerRadius() const;

    QColor color() const;


    void animationStart();
    void animationFinished();
    void animationPaused();

    void startInfiniteAnimation();
    void stopInfiniteAnimation();
    void pauseInfiniteAnimation();

public slots:
    void setValue(int value);
    void setMaximum(int maximum);

    void setInnerRadius(qreal innerRadius);
    void setOuterRadius(qreal outerRadius);

    void setColor(QColor color);

signals:
    void valueChanged(int);
    void maximumChanged(int);

protected:
    void paintEvent(QPaintEvent *);

private slots:
    void setInfiniteAnimationValue(qreal value);
    void setVisibleValue(int value);

private:
    void initAnimation();
    QString key() const;
    QPixmap generatePixmap() const;
    qreal infiniteAnimationValue() const;
    int visibleValue() const;

private:
    QScopedPointer<privateStruct> d;
};


-------------------------------------

.cpp


/////////////////////////////////////////////////////////////////////////////
// Date of creation: 04.07.2013
// Creator: Alexander Egorov aka mofr
// Modifier : sp.Park 2018.10.30
// Authors: mofr
/////////////////////////////////////////////////////////////////////////////

#include "ProgressCircle.h"
#include <QPainter>
#include <QPixmapCache>

struct ProgressCircle::privateStruct
{
    qreal mInnerRadius;
    qreal mOuterRadius;
    qreal mInfiniteAnimationValue;
    QColor mColor;

    QPropertyAnimation mValueAnimation;
    QPropertyAnimation mInfiniteAnimation;

    int mValue = 0;
    int mMaximum = 0;
    int mVisibleValue = 0;
    bool mIsInfinite = true;
};


ProgressCircle::ProgressCircle(QWidget *parent) :
    QWidget(parent),
    d(new privateStruct)
{
    d->mValueAnimation.setTargetObject(this);
    d->mValueAnimation.setPropertyName("visibleValue");

    d->mInfiniteAnimation.setTargetObject(this);
    d->mInfiniteAnimation.setPropertyName("infiniteAnimationValue");
    d->mInfiniteAnimation.setLoopCount(-1);//infinite
    d->mInfiniteAnimation.setDuration(1000);
    d->mInfiniteAnimation.setStartValue(0.0);
    d->mInfiniteAnimation.setEndValue(1.0);
}

ProgressCircle::~ProgressCircle()
{

}

int ProgressCircle::value() const
{
    return d->mValue;
}

int ProgressCircle::maximum() const
{
    return d->mMaximum;
}

qreal ProgressCircle::innerRadius() const
{
    return d->mInnerRadius;
}

qreal ProgressCircle::outerRadius() const
{
    return d->mOuterRadius;
}

QColor ProgressCircle::color() const
{
    return d->mColor;
}

void ProgressCircle::initAnimation()
{
    d->mColor = QColor(110, 190, 235);
    d->mInnerRadius = 0.6;
    d->mOuterRadius = 1.0;

    QPropertyAnimation * progressCircleAnimation = new QPropertyAnimation(this, "outerRadius", this);
    progressCircleAnimation->setDuration(1000);
    progressCircleAnimation->setEasingCurve(QEasingCurve::OutQuad);
    progressCircleAnimation->setStartValue(0.0);
    progressCircleAnimation->setEndValue(d->mOuterRadius);
    progressCircleAnimation->start(QAbstractAnimation::DeleteWhenStopped);

    progressCircleAnimation = new QPropertyAnimation(this, "innerRadius", this);
    progressCircleAnimation->setDuration(500);
    progressCircleAnimation->setEasingCurve(QEasingCurve::OutQuad);
    progressCircleAnimation->setEndValue(d->mInnerRadius);
    progressCircleAnimation->start(QAbstractAnimation::DeleteWhenStopped);

    progressCircleAnimation = new QPropertyAnimation(this, "color", this);
    progressCircleAnimation->setDuration(500);
    progressCircleAnimation->setEasingCurve(QEasingCurve::OutQuad);
    progressCircleAnimation->setEndValue(d->mColor);
    progressCircleAnimation->start(QAbstractAnimation::DeleteWhenStopped);
}

void ProgressCircle::animationStart()
{
    this->setValue(0);
    this->initAnimation();

    d->mIsInfinite = true;
    d->mInfiniteAnimation.start();
}

void ProgressCircle::animationFinished()
{
    d->mIsInfinite = false;
    d->mInfiniteAnimation.stop();

    this->setValue(this->maximum());

    QPropertyAnimation * animation = new QPropertyAnimation(this, "outerRadius", this);
    animation->setDuration(1000);
    animation->setEasingCurve(QEasingCurve::OutQuad);
    animation->setEndValue(0.5);
    animation->start(QAbstractAnimation::DeleteWhenStopped);

    animation = new QPropertyAnimation(this, "innerRadius", this);
    animation->setDuration(500);
    animation->setEasingCurve(QEasingCurve::OutQuad);
    animation->setEndValue(0.0);
    animation->start(QAbstractAnimation::DeleteWhenStopped);

    QColor color(155,219,58);
    animation = new QPropertyAnimation(this, "color", this);
    animation->setDuration(500);
    animation->setEasingCurve(QEasingCurve::OutQuad);
    animation->setEndValue(color);
    animation->start(QAbstractAnimation::DeleteWhenStopped);
}

void ProgressCircle::animationPaused()
{
    QPropertyAnimation * animation = new QPropertyAnimation(this, "outerRadius", this);
    animation->setDuration(1000);
    animation->setEasingCurve(QEasingCurve::OutQuad);
    animation->setEndValue(0.5);
    animation->start(QAbstractAnimation::DeleteWhenStopped);

    animation = new QPropertyAnimation(this, "innerRadius", this);
    animation->setDuration(500);
    animation->setEasingCurve(QEasingCurve::OutQuad);
    animation->setEndValue(0.0);
    animation->start(QAbstractAnimation::DeleteWhenStopped);

    QColor color(255,100,100);
    animation = new QPropertyAnimation(this, "color", this);
    animation->setDuration(500);
    animation->setEasingCurve(QEasingCurve::OutQuad);
    animation->setEndValue(color);
    animation->start(QAbstractAnimation::DeleteWhenStopped);
}

void ProgressCircle::startInfiniteAnimation()
{
    this->animationStart();
}

void ProgressCircle::stopInfiniteAnimation()
{
    this->animationFinished();
}

void ProgressCircle::pauseInfiniteAnimation()
{
    d->mInfiniteAnimation.pause();
}

void ProgressCircle::setValue(int value)
{       
    if(d->mIsInfinite == true)
        return;

    if(value < 0)
        value = 0;

    if((qFuzzyCompare(d->mInnerRadius, 0.6) == false) || (qFuzzyCompare(d->mOuterRadius, 1.0) == false))
    {
        this->initAnimation();

        if(this->maximum() == 0)
            this->setMaximum(100);
    }

    if(d->mValue != value)
    {
        d->mValueAnimation.stop();
        d->mValueAnimation.setEndValue(value);
        d->mValueAnimation.setDuration(250);
        d->mValueAnimation.start();

        d->mValue = value;
        emit valueChanged(value);
    }
}

void ProgressCircle::setMaximum(int maximum)
{
    if(maximum < 0)
        maximum = 0;

    if(d->mMaximum != maximum)
    {
        d->mMaximum = maximum;
        this->update();
        emit maximumChanged(maximum);
    }
}

void ProgressCircle::setInnerRadius(qreal innerRadius)
{
    if(innerRadius > 1.0)
        innerRadius = 1.0;

    if(innerRadius < 0.0)
        innerRadius = 0.0;

    if(d->mInnerRadius != innerRadius)
    {
        d->mInnerRadius = innerRadius;
        this->update();
    }
}

void ProgressCircle::setOuterRadius(qreal outerRadius)
{
    if(outerRadius > 1.0)
        outerRadius = 1.0;

    if(outerRadius < 0.0)
        outerRadius = 0.0;

    if(d->mOuterRadius != outerRadius)
    {
        d->mOuterRadius = outerRadius;
        this->update();
    }
}

void ProgressCircle::setColor(QColor color)
{
    if(color != d->mColor)
    {
        d->mColor = color;
        this->update();
    }
}

QRectF squared(QRectF rect)
{
    if(rect.width() > rect.height())
    {
        qreal diff = rect.width() - rect.height();
        return rect.adjusted(diff/2, 0, -diff/2, 0);
    }
    else
    {
        qreal diff = rect.height() - rect.width();
        return rect.adjusted(0, diff/2, 0, -diff/2);
    }
}

void ProgressCircle::paintEvent(QPaintEvent *)
{
    QPixmap pixmap;
    if (!QPixmapCache::find(key(), pixmap))
    {
        pixmap = generatePixmap();
        QPixmapCache::insert(key(), pixmap);
    }

    // Draw pixmap at center of item
    QPainter painter(this);
    painter.drawPixmap( 0.5 * ( width() - pixmap.width() ), 0.5 * ( height() - pixmap.height() ), pixmap );
}

void ProgressCircle::setInfiniteAnimationValue(qreal value)
{
    d->mInfiniteAnimationValue = value;
    this->update();
}

void ProgressCircle::setVisibleValue(int value)
{
    if(d->mVisibleValue != value)
    {
        d->mVisibleValue = value;
        this->update();
    }
}

QString ProgressCircle::key() const
{
    return QString("%1,%2,%3,%4,%5,%6,%7,%8")
            .arg(d->mInfiniteAnimationValue)
            .arg(d->mVisibleValue)
            .arg(d->mMaximum)
            .arg(d->mInnerRadius)
            .arg(d->mOuterRadius)
            .arg(this->width())
            .arg(this->height())
            .arg(d->mColor.rgb());
}

QPixmap ProgressCircle::generatePixmap() const
{
    QPixmap pixmap(squared(rect()).size().toSize());
    pixmap.fill(QColor(0,0,0,0));
    QPainter painter(&pixmap);

    painter.setRenderHint(QPainter::Antialiasing, true);

    QRectF rect = pixmap.rect().adjusted(1,1,-1,-1);
    qreal margin = rect.width()*(1.0 - d->mOuterRadius)/2.0;
    rect.adjust(margin,margin,-margin,-margin);
    qreal innerRadius = d->mInnerRadius*rect.width()/2.0;

    //background grey circle
    painter.setBrush(QColor(225,225,225));
    painter.setPen(QColor(225,225,225));
    painter.drawPie(rect, 0, 360*16);

    painter.setBrush(d->mColor);
    painter.setPen(d->mColor);

    if(d->mIsInfinite == true)
    {
        //draw as infinite process
        int startAngle = (-d->mInfiniteAnimationValue) * 360 * 16;
        int spanAngle = 0.15 * 360 * 16;
        painter.drawPie(rect, startAngle, spanAngle);
    }
    else
    {
        int value = qMin(d->mVisibleValue, d->mMaximum);
        int startAngle = 90 * 16;
        int spanAngle = -qreal(value) * 360 * 16 / d->mMaximum;

        painter.drawPie(rect, startAngle, spanAngle);
    }

    //inner circle and frame
    painter.setBrush(QColor(255,255,255));
    painter.setPen(QColor(0,0,0, 60));
    painter.drawEllipse(rect.center(), innerRadius, innerRadius);

    //outer frame
    painter.drawArc(rect, 0, 360*16);

    return pixmap;
}

qreal ProgressCircle::infiniteAnimationValue() const
{
    return d->mInfiniteAnimationValue;
}

int ProgressCircle::visibleValue() const
{
    return d->mVisibleValue;
}




해당코드는  Git 허브에서 원본소스를 가져왔으며

제가 수정하였습니다.


문제시 삭제하겠습니다.


코드 수정 배포시 

원제작자, 수정자 남겨주시기바랍니다.


사용법은 위젯위에  Promote하시던가 그냥 만들어서 setvalue같은거 써보시면 됍니다 :)