Qt Writes Custom Control 33-Picture Switching Animation

Posted by Duell on Sun, 21 Jul 2019 16:52:52 +0200

I. Preface

In many graphics software, when switching pictures, you can bring animation transition or switching effect, which is more human-oriented. In fact, it is mainly dazzling, such as shutters, transparency changes, lower left corner flying in, etc. No matter how many kinds of effects, the core is around QPainter to carry out the corresponding pictures of various animation effects. The region is calculated and plotted dynamically, and linear interpolation is generated with QProperty Animation animation attributes. For example, it can be fast in the middle and slow at both ends when it comes in. At present, there are nine types of animation, which will continue to increase in the later period.

  • 1: Image 1 fades away and image 2 appears.
  • 2: Louver effect
  • 3: Image flipped from right to left
  • 4: Horizontal segmentation from outside to inside
  • 5: Image 1 exits the visual area from left to right, while Image 2 enters the visual area from left to right.
  • 6: Image 1 exits the visual area from left to right, while Image 2 enters the visual area from left to right.
  • 7: Image 1 exits the visual area from bottom to top, while Image 2 enters the visual area from bottom to top.
  • 8: Image 1 exits the visual area from top to bottom, while Image 2 enters the visual area from top to bottom.
  • 9: Image 1 does not move, while Image 2 moves from lower right to upper left.

II. Functions of Realization

  • 1: Support a variety of waiting style arc style rotary circular style triangular arc style ring style
  • 2: Range values and current values can be set
  • 3: Foreground color and background color can be set
  • 4: Clockwise and counterclockwise rotation can be set
  • 5: Support arbitrary scaling
  • 6: Support setting rotation speed interval

III. EFFECT CHARACTERISTICS

Header file code

#ifndef IMAGEANIMATION_H
#define IMAGEANIMATION_H

/**
 * Author of Picture Switching Animation Control: Zhao Yanbo (QQ:408815041 zyb920@hotmail.com) 2019-6-10
 * 1:Animation type can be set, default 9, later will increase more
 * FadeEffect = 0,             //Image 1 fades and image 2 appears.
 * BlindsEffect = 1,           //Blinds effect
 * FlipRightToLeft = 2,        //Image flipped from right to left
 * OutsideToInside = 3,        //Horizontal segmentation from outside to inside
 * MoveLeftToRightEffect = 4,  //Image 1 exits the visual area from left to right, while image 2 enters the visual area from left to right.
 * MoveRightToLeftEffect = 5,  //Image 1 exits the visual area from left to right, while image 2 enters the visual area from left to right.
 * MoveBottomToUpEffect = 6,   //Image 1 exits the visible region from bottom to top, while image 2 enters the visible region from bottom to top.
 * MoveUpToBottomEffect = 7,   //Image 1 exits the visible region from top to bottom, while image 2 enters the visible region from top to bottom.
 * MoveBottomToLeftUpEffect = 8//Image 1 does not move, while image 2 moves from bottom right to top left.
 * 2:You can set the path names or pictures of two pictures.
 * 3:Settable animation factor
 */

#include <QWidget>

class QPropertyAnimation;

#ifdef quc
#if (QT_VERSION < QT_VERSION_CHECK(5,7,0))
#include <QtDesigner/QDesignerExportWidget>
#else
#include <QtUiPlugin/QDesignerExportWidget>
#endif

class QDESIGNER_WIDGET_EXPORT ImageAnimation : public QWidget
#else
class ImageAnimation : public QWidget
#endif

{
    Q_OBJECT
    Q_ENUMS(AnimationType)
    Q_PROPERTY(float factor READ getFactor WRITE setFactor)
    Q_PROPERTY(QString imageName1 READ getImageName1 WRITE setImageName1)
    Q_PROPERTY(QString imageName2 READ getImageName2 WRITE setImageName2)
    Q_PROPERTY(QPixmap pixmap1 READ getPixmap1 WRITE setPixmap1)
    Q_PROPERTY(QPixmap pixmap2 READ getPixmap2 WRITE setPixmap2)
    Q_PROPERTY(AnimationType animationType READ getAnimationType WRITE setAnimationType)

public:
    enum AnimationType {
        FadeEffect = 0,             //Image 1 fades and image 2 appears.
        BlindsEffect = 1,           //Blinds effect
        FlipRightToLeft = 2,        //Image flipped from right to left
        OutsideToInside = 3,        //Horizontal segmentation from outside to inside
        MoveLeftToRightEffect = 4,  //Image 1 exits the visual area from left to right, while image 2 enters the visual area from left to right.
        MoveRightToLeftEffect = 5,  //Image 1 exits the visual area from left to right, while image 2 enters the visual area from left to right.
        MoveBottomToUpEffect = 6,   //Image 1 exits the visible region from bottom to top, while image 2 enters the visible region from bottom to top.
        MoveUpToBottomEffect = 7,   //Image 1 exits the visible region from top to bottom, while image 2 enters the visible region from top to bottom.
        MoveBottomToLeftUpEffect = 8//Image 1 does not move, while image 2 moves from bottom right to top left.
    };

    explicit ImageAnimation(QWidget *parent = 0);
    ~ImageAnimation();

protected:
    void paintEvent(QPaintEvent *);
    void fadeEffect(QPainter *painter, const QRect &rect, float factor, const QPixmap &pixmap1, const QPixmap &pixmap2);
    void blindsEffect(QPainter *painter, const QRect &rect, float factor, const QPixmap &pixmap1, const QPixmap &pixmap2);
    void flipRightToLeft(QPainter *painter, const QRect &rect, float factor, const QPixmap &pixmap1, const QPixmap &pixmap2);
    void outsideToInside(QPainter *painter, const QRect &rect, float factor, const QPixmap &pixmap1, const QPixmap &pixmap2);
    void moveLeftToRightEffect(QPainter *painter, const QRect &rect, float factor, const QPixmap &pixmap1, const QPixmap &pixmap2);
    void moveRightToLeftEffect(QPainter *painter, const QRect &rect, float factor, const QPixmap &pixmap1, const QPixmap &pixmap2);
    void moveBottomToUpEffect(QPainter *painter, const QRect &rect, float factor, const QPixmap &pixmap1, const QPixmap &pixmap2);
    void moveUpToBottomEffect(QPainter *painter, const QRect &rect, float factor, const QPixmap &pixmap1, const QPixmap &pixmap2);
    void moveBottomToLeftUpEffect(QPainter *painter, const QRect &rect, float factor, const QPixmap &pixmap1, const QPixmap &pixmap2);

private:
    float factor;                   //Animation factor (change between 0 - 1.0)
    QString imageName1;             //Picture 1 Path Name
    QString imageName2;             //Picture 2 Path Name
    QPixmap pixmap1;                //Picture 1
    QPixmap pixmap2;                //Picture 2
    AnimationType animationType;    //Types of animation effects

    QPropertyAnimation *animation;  //Animation Attributes

public:
    float getFactor()               const;
    QString getImageName1()         const;
    QString getImageName2()         const;
    QPixmap getPixmap1()            const;
    QPixmap getPixmap2()            const;
    AnimationType getAnimationType()const;

    QSize sizeHint()                const;
    QSize minimumSizeHint()         const;

public Q_SLOTS:
    //Setting Animation Factor
    void setFactor(float factor);

    //Set Picture 1 + Picture 2 Path Name
    void setImageName1(const QString &imageName1);
    void setImageName2(const QString &imageName2);

    //Set Picture 1 + Picture 2
    void setPixmap1(const QPixmap &pixmap1);
    void setPixmap2(const QPixmap &pixmap2);

    //Setting Animation Types
    void setAnimationType(const AnimationType &animationType);

    //Start + Stop Animation
    void start();
    void stop();
};

#endif // IMAGEANIMATION_H


V. Core Code

void ImageAnimation::paintEvent(QPaintEvent *)
{
    if (pixmap1.isNull() || pixmap2.isNull()) {
        return;
    }

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

    switch (animationType) {
    case 0:
        fadeEffect(&painter, geometry(), factor, pixmap1, pixmap2);
        break;
    case 1:
        blindsEffect(&painter, geometry(), factor, pixmap1, pixmap2);
        break;
    case 2:
        flipRightToLeft(&painter, geometry(), factor, pixmap1, pixmap2);
        break;
    case 3:
        outsideToInside(&painter, geometry(), factor, pixmap1, pixmap2);
        break;
    case 4:
        moveLeftToRightEffect(&painter, geometry(), factor, pixmap1, pixmap2);
        break;
    case 5:
        moveRightToLeftEffect(&painter, geometry(), factor, pixmap1, pixmap2);
        break;
    case 6:
        moveBottomToUpEffect(&painter, geometry(), factor, pixmap1, pixmap2);
        break;
    case 7:
        moveUpToBottomEffect(&painter, geometry(), factor, pixmap1, pixmap2);
        break;
    case 8:
        moveBottomToLeftUpEffect(&painter, geometry(), factor, pixmap1, pixmap2);
        break;
    default:
        break;
    }
}

void ImageAnimation::fadeEffect(QPainter *painter, const QRect &rect, float factor, const QPixmap &pixmap1, const QPixmap &pixmap2)
{
    int w = rect.width();
    int h = rect.height();
    int alpha = 255 * (1.0f - factor);

    QPixmap alphaPixmap(pixmap1.size());
    alphaPixmap.fill(Qt::transparent);

    QPainter p1(&alphaPixmap);
    p1.setCompositionMode(QPainter::CompositionMode_Source);
    p1.drawPixmap(0, 0, pixmap1);
    p1.setCompositionMode(QPainter::CompositionMode_DestinationIn);
    p1.fillRect(alphaPixmap.rect(), QColor(0, 0, 0, alpha));
    p1.end();

    int x = (w - pixmap1.width()) / 2;
    int y = (h - pixmap1.height()) / 2;
    painter->drawPixmap(x, y, alphaPixmap);

    alpha = 255 * (factor);
    alphaPixmap.fill(Qt::transparent);
    QPainter p2(&alphaPixmap);
    p2.setCompositionMode(QPainter::CompositionMode_Source);
    p2.drawPixmap(0, 0, pixmap2);
    p2.setCompositionMode(QPainter::CompositionMode_DestinationIn);
    p2.fillRect(alphaPixmap.rect(), QColor(0, 0, 0, alpha));
    p2.end();

    painter->drawPixmap(x, y, alphaPixmap);
}

void ImageAnimation::blindsEffect(QPainter *painter, const QRect &rect, float factor, const QPixmap &pixmap1, const QPixmap &pixmap2)
{
    int i, n, w, h, x1, y1, x2, y2, dh, ddh;

    w = rect.width();
    h = rect.height();
    x1 = (w - pixmap1.width()) / 2;
    y1 = (h - pixmap1.height()) / 2;
    x2 = (w - pixmap2.width()) / 2;
    y2 = (h - pixmap2.height()) / 2;

    painter->drawPixmap(x1, y1, pixmap1);

    n = 10;
    dh = pixmap2.height() / n;
    ddh = factor * dh;
    if (ddh < 1) {
        ddh = 1;
    }

    for(i = 0; i < n; i++) {
        painter->drawPixmap(x2, y2 + i * dh, pixmap2, 0, i * dh, pixmap2.width(), ddh);
    }
}

void ImageAnimation::flipRightToLeft(QPainter *painter, const QRect &rect, float factor, const QPixmap &pixmap1, const QPixmap &pixmap2)
{
    int x1, y1, x2, y2, w, h;
    float rot;
    QTransform trans;

    w = rect.width();
    h = rect.height();
    x1 = (w - pixmap1.width()) / 2;
    y1 = (h - pixmap1.height()) / 2;
    x2 = (w - pixmap2.width()) / 2;
    y2 = (h - pixmap2.height()) / 2;

    rot = factor * 90.0f;
    trans.translate(w * (1 - factor), h / 2);
    trans.rotate(rot, Qt::YAxis);
    trans.translate(-w, -h / 2);

    painter->setTransform(trans);
    painter->drawPixmap(x1, y1, pixmap1);
    painter->resetTransform();

    trans.reset();
    rot = 90 * (factor - 1);
    trans.translate(w * (1 - factor), h / 2);
    trans.rotate(rot, Qt::YAxis);
    trans.translate(0, -h / 2);

    painter->setTransform(trans);
    painter->drawPixmap(x2, y2, pixmap2);
    painter->resetTransform();
}

void ImageAnimation::outsideToInside(QPainter *painter, const QRect &rect, float factor, const QPixmap &pixmap1, const QPixmap &pixmap2)
{
    int   w, h, x1, y1, x2, y2, x3, y3, dh, ddh;

    w = rect.width();
    h = rect.height();
    x1 = (w - pixmap1.width()) / 2;
    y1 = (h - pixmap1.height()) / 2;
    painter->drawPixmap(x1, y1, pixmap1);

    dh = pixmap2.height() / 2;
    ddh = factor * dh;
    if (ddh < 1) {
        ddh = 1;
    }

    x2 = (w - pixmap2.width()) / 2;
    y2 = (h - pixmap2.height()) / 2;
    painter->drawPixmap(x2, y2, pixmap2, 0, 0, pixmap2.width(), ddh);

    x3 = (w - pixmap2.width()) / 2;
    y3 =  dh * (1.0f - factor) + h / 2;
    if(y3 != h / 2) {
        y3 += 1;
    }

    painter->drawPixmap(x3, y3, pixmap2, 0, pixmap2.height() - ddh, pixmap2.width(), ddh);
}

void ImageAnimation::moveLeftToRightEffect(QPainter *painter, const QRect &rect, float factor, const QPixmap &pixmap1, const QPixmap &pixmap2)
{
    int x, y, w, h, x1, y1, x2, y2;

    w = rect.width();
    h = rect.height();
    x1 = (w - pixmap1.width()) / 2;
    y1 = (h - pixmap1.height()) / 2;
    x2 = (w - pixmap2.width()) / 2;
    y2 = (h - pixmap2.height()) / 2;

    x = x1 + w * factor;
    y = y1;
    painter->drawPixmap(x, y, pixmap1);

    x = x2 + w * (factor - 1);
    y = y2;
    painter->drawPixmap(x, y, pixmap2);
}

Introduction of Control

  1. More than 149 exquisite controls, covering a variety of dashboards, progress bars, progress balls, compasses, curves, rulers, thermometers, navigation bars, navigation bars, flatui, highlighted buttons, sliding selectors, the lunar calendar and so on. Far more controls than qwt integrates.
  2. Each class can be separated into a separate control, zero-coupling, each control has a header file and an implementation file, independent of other files, to facilitate the integration of a single control in the form of source code into the project, less code. The control classes of qwt are interlinked and highly coupled. If you want to use one of the controls, you must include all the code.
  3. All pure Qt writing, QWidget+QPainter drawing, support any Qt version from Qt4.6 to Qt5.12, support mingw, msvc, gcc and other compilers, support any operating system such as windows+linux+mac + embedded linux, no scrambling, can be directly integrated into Qt Creator, as with its own controls, most of the effects as long as set up. Several attributes can be used, which is very convenient.
  4. Each control has a corresponding separate DEMO containing the source code of the control, which is convenient for reference. It also provides an integrated DEMO for all controls.
  5. The source code of each control has detailed Chinese annotations, which are compiled in accordance with the unified design specifications. It is convenient to learn how to compile custom controls.
  6. Each control's default color matching and demo's corresponding color matching are very beautiful.
  7. More than 130 visible controls and 6 invisible controls.
  8. Some controls provide a variety of style choices, a variety of indicator style choices.
  9. All controls adapt to form stretching changes.
  10. Integrate custom control property designer, support drag design, WYSIWYG, support import and export xml format.
  11. With activex control demo, all controls can run directly in ie browser.
  12. Integrate fontawesome graphic fonts + hundreds of graphic fonts collected by Alibaba iconfont to enjoy the fun of graphic fonts.
  13. All controls finally generate a dll Dynamic Library file, which can be directly integrated into the qtcreator for dragging design use.
  14. At present, there is a version of qml, pyqt version will be considered later, if the user demand is large.

7. SDK Download

  • SDK Download Link: https://pan.baidu.com/s/1A5Gd77kExm8Co5ckT51vvQ Extraction code: 877p
  • The download link contains various versions of dynamic library files, header files of all controls, using demo, custom control + property designer.
  • Custom control plug-in open dynamic library dll use (permanent free), without any back door and restrictions, please feel free to use.
  • At present, 26 versions of dll have been provided, including qt5.12.3 MSVC 2017 32 + 64 MinGW 32 + 64.
  • Increase control and improve control from time to time, update SDK from time to time. Welcome to make suggestions. Thank you!
  • widget version (QQ: 517216493) qml version (QQ: 373955953) camel (QQ: 278969898).
  • The Way to Advance Qt in Taoge's Knowledge Column https://zhuanlan.zhihu.com/TaoQt
  • Welcome to pay attention to Wechat Public Number, C++/Python, learning methods, writing skills, popular technology, career development and other content, more dry goods, more benefits!

Topics: Mobile Qt SDK Qt5 Linux