c++ Qt -创建带有图像的按钮,图像在hoverEvent上同时淡出和淡入

enxuqcxy  于 2022-12-24  发布在  其他
关注(0)|答案(1)|浏览(147)

在C ++/Qt6中,我想开发一个带有动画的按钮(我想我必须使用QParallelAnimationGroup),该按钮的图标是在另一个图像中淡出的同时淡出一个图像。
以下是我想要的(与电影制作人制作):
button fade out-fade in images, demo of the effect I'm looking for
我已经开发了一个带有动画的QToolButton,它可以让按钮淡出,然后用一个新图标淡入(按顺序)。我使用了QPropertyAnimation和QSequentialAnimationGroup。
. h

#ifndef FADINGIMAGESPUSHBUTTON_H
#define FADINGIMAGESPUSHBUTTON_H

#include <QToolButton>
#include <QPropertyAnimation>
#include <QGraphicsOpacityEffect>
#include <QSequentialAnimationGroup>

class FadingImagesPushButton : public QToolButton
{
    Q_OBJECT
public:
    FadingImagesPushButton(QWidget *parent = nullptr, const QString & title = "", const QString & imageNormalPath = "", const QString & imageHoverPath = "");
protected:
    static const int s_AnimDuration;
    virtual bool event(QEvent * e) override;
    void hoverEnter();
    void hoverLeave();
    QString m_imageNormalPath;
    QString m_imageHoverPath;
    int m_curTimeAnim_toHover;
    int m_curTimeAnim_toNormal;

    QPropertyAnimation *m_AnimNormalFadeOut;
    QPropertyAnimation *m_AnimHoverFadeIn;
    QPropertyAnimation *m_AnimHoverFadeOut;
    QPropertyAnimation *m_AnimNormalFadeIn;
    QSequentialAnimationGroup *m_toHoverAnimGroup;
    QSequentialAnimationGroup *m_toNormalAnimGroup;

    QGraphicsOpacityEffect *m_effect;
protected slots:
    void switchToHoverImage();
    void switchToNormalImage();
    void deleteAndNullToHoverAnimGroup();
    void deleteAndNullToNormalAnimGroup();
};

#endif // FADINGIMAGESPUSHBUTTON_H

. cpp

#include "fadingimagespushbutton.h"
#include <QEvent>

const int FadingImagesPushButton::s_AnimDuration = 800;

FadingImagesPushButton::FadingImagesPushButton(QWidget *parent,const QString & title, const QString & imageNormalPath, const QString & imageHoverPath)
    :QToolButton(parent),m_imageNormalPath(imageNormalPath),m_imageHoverPath(imageHoverPath)
{
    setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
    setFixedSize(275,280);
    setIconSize(QSize(270,240));
    QFont font;
    font.setPointSize(18);
    setAttribute(Qt::WA_Hover);
    setFont(font);
    setText(title);
    setIcon(QIcon(m_imageNormalPath));

    m_effect = new QGraphicsOpacityEffect(this);
    setGraphicsEffect(m_effect);

    m_toHoverAnimGroup = nullptr;
    m_toNormalAnimGroup = nullptr;
}

bool FadingImagesPushButton::event(QEvent *e)
{
    switch(e->type())
        {
        case QEvent::HoverEnter:
            hoverEnter();
            return QToolButton::event(e);
        case QEvent::HoverLeave:
            hoverLeave();
            return QToolButton::event(e);
        default:
            break;
        }
    return QToolButton::event(e);
}

void FadingImagesPushButton::hoverEnter()
{
    int realDurationFadeOut = s_AnimDuration;
    int realDurationFadeIn = s_AnimDuration;
    if(m_toNormalAnimGroup)
    {
        int animGroupDuration = m_toNormalAnimGroup->currentTime();
        if(animGroupDuration < s_AnimDuration)
        {
            realDurationFadeOut = 0;
            realDurationFadeIn = animGroupDuration;
        }
        else
        {
            realDurationFadeOut = animGroupDuration - s_AnimDuration;
            realDurationFadeIn = s_AnimDuration;
        }
        m_toNormalAnimGroup->stop();
    }

    if(realDurationFadeOut !=0)
    {
        m_AnimNormalFadeOut = new QPropertyAnimation(m_effect,"opacity");
        m_AnimNormalFadeOut->setDuration(realDurationFadeOut);
        m_AnimNormalFadeOut->setStartValue(1.*((float)realDurationFadeOut/(float)s_AnimDuration));
        m_AnimNormalFadeOut->setEndValue(0.);
        m_AnimNormalFadeOut->setEasingCurve(QEasingCurve::InBack);
    }
    m_AnimHoverFadeIn = new QPropertyAnimation(m_effect,"opacity");
    m_AnimHoverFadeIn->setDuration(realDurationFadeIn);
    m_AnimHoverFadeIn->setStartValue(1. - ((float)realDurationFadeIn/(float)s_AnimDuration));
    m_AnimHoverFadeIn->setEndValue(1.);
    m_AnimHoverFadeIn->setEasingCurve(QEasingCurve::InBack);

    m_toHoverAnimGroup = new QSequentialAnimationGroup(this);
    if(realDurationFadeOut !=0)
        m_toHoverAnimGroup->addAnimation(m_AnimNormalFadeOut);
    m_toHoverAnimGroup->addAnimation(m_AnimHoverFadeIn);

    connect(m_toHoverAnimGroup,&QSequentialAnimationGroup::currentAnimationChanged, this, &FadingImagesPushButton::switchToHoverImage);
    connect(m_toHoverAnimGroup,&QSequentialAnimationGroup::finished, this, &FadingImagesPushButton::deleteAndNullToHoverAnimGroup);

    m_toHoverAnimGroup->start();
}

void FadingImagesPushButton::hoverLeave()
{
    int realDurationFadeOut = s_AnimDuration;
    int realDurationFadeIn = s_AnimDuration;
    if(m_toHoverAnimGroup)
    {
        int animGroupDuration = m_toHoverAnimGroup->currentTime();
        if(animGroupDuration < s_AnimDuration)
        {
            realDurationFadeOut = 0;
            realDurationFadeIn = animGroupDuration;
        }
        else
        {
            realDurationFadeOut = animGroupDuration - s_AnimDuration;
            realDurationFadeIn = s_AnimDuration;
        }
        m_toHoverAnimGroup->stop();
    }

    if(realDurationFadeOut !=0)
    {
        m_AnimHoverFadeOut = new QPropertyAnimation(m_effect,"opacity");
        m_AnimHoverFadeOut->setDuration(realDurationFadeOut);
        m_AnimHoverFadeOut->setStartValue(1.*((float)realDurationFadeOut/(float)s_AnimDuration));
        m_AnimHoverFadeOut->setEndValue(0.);
        m_AnimHoverFadeOut->setEasingCurve(QEasingCurve::InBack);
    }

    m_AnimNormalFadeIn = new QPropertyAnimation(m_effect,"opacity");
    m_AnimNormalFadeIn->setDuration(realDurationFadeIn);
    m_AnimNormalFadeIn->setStartValue(1.-((float)realDurationFadeIn/(float)s_AnimDuration));
    m_AnimNormalFadeIn->setEndValue(1.);
    m_AnimNormalFadeIn->setEasingCurve(QEasingCurve::InBack);

    m_toNormalAnimGroup = new QSequentialAnimationGroup(this);
    if(realDurationFadeOut !=0)
        m_toNormalAnimGroup->addAnimation(m_AnimHoverFadeOut);
    m_toNormalAnimGroup->addAnimation(m_AnimNormalFadeIn);

    connect(m_toNormalAnimGroup,&QSequentialAnimationGroup::currentAnimationChanged, this, &FadingImagesPushButton::switchToNormalImage);
    connect(m_toNormalAnimGroup,&QSequentialAnimationGroup::finished, this, &FadingImagesPushButton::deleteAndNullToNormalAnimGroup);

    m_toNormalAnimGroup->start();
}

void FadingImagesPushButton::switchToHoverImage()
{
    setIcon(QIcon(m_imageHoverPath));
}

void FadingImagesPushButton::switchToNormalImage()
{
    setIcon(QIcon(m_imageNormalPath));
}

void FadingImagesPushButton::deleteAndNullToHoverAnimGroup()
{
    m_toHoverAnimGroup = nullptr;
}

void FadingImagesPushButton::deleteAndNullToNormalAnimGroup()
{
    m_toNormalAnimGroup = nullptr;
}

演示中的结果:
button fade out-fade in images, already done in sequance

7z5jn7bk

7z5jn7bk1#

我设法应用预期的效果,这里是代码.
注意:在我的例子中,第二个图像(悬停)是我应用在正常图像之上的一个层,但是如果你想合并两个不同的图像,只需稍微改变applyComposition()
NB2:我们需要测试计算负载。每50毫秒应用两个QPainter可能不是最好的方法。也许用QPainter预构建16个图像会更好
.h

#ifndef FADINGIMAGESPUSHBUTTON_H
#define FADINGIMAGESPUSHBUTTON_H

#include <QToolButton>
#include <QElapsedTimer>

class FadingImagesPushButton : public QToolButton
{
    Q_OBJECT
public:
    FadingImagesPushButton(QWidget *parent = nullptr, const QString & title = "", const QString & imageNormalPath = "", const QString & imageHoverPath = "");
protected:
    static const int s_AnimDuration;
    virtual bool event(QEvent * e) override;
    QString m_imageNormalPath;
    QString m_imageHoverPath;
    QElapsedTimer toHoverTimer;
    QElapsedTimer toNormalTimer;
    void applyComposition();
    qreal m_currentOpacity;
    QImage m_hoverLayer;
    QImage m_normalImage;
protected slots:
    void hoverEnter();
    void hoverLeave();
};

#endif // FADINGIMAGESPUSHBUTTON_H

.cpp

#include "fadingimagespushbutton.h"
#include <QEvent>
#include <QPainter>
#include <QImage>
#include <QTimer>

const int FadingImagesPushButton::s_AnimDuration = 800;

FadingImagesPushButton::FadingImagesPushButton(QWidget *parent,const QString & title, const QString & imageNormalPath, const QString & imageHoverPath)
    :QToolButton(parent),m_imageNormalPath(imageNormalPath),m_imageHoverPath(imageHoverPath)
{
    setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
    setFixedSize(220,255);
    setIconSize(QSize(215,215));
    QFont font;
    font.setPointSize(18);
    setFont(font);
    setText(title);
    setAttribute(Qt::WA_Hover);
    setIcon(QIcon(m_imageNormalPath));
    m_hoverLayer.load(m_imageHoverPath,"PNG");
    m_normalImage.load(m_imageNormalPath,"PNG");
}

bool FadingImagesPushButton::event(QEvent *e)
{
    switch(e->type())
        {
        case QEvent::HoverEnter:
            toHoverTimer.start();
            hoverEnter();
            return QToolButton::event(e);
        case QEvent::HoverLeave:
            toNormalTimer.start();
            hoverLeave();
            return QToolButton::event(e);
        default:
            break;
        }
    return QToolButton::event(e);
}

void FadingImagesPushButton::hoverEnter()
{
    if(toNormalTimer.elapsed() > s_AnimDuration)
    {
        m_currentOpacity = 1. - (float)toHoverTimer.elapsed() / (float)s_AnimDuration;
        if(m_currentOpacity < 0.)
            m_currentOpacity = 0.;
        applyComposition();
        if(m_currentOpacity > 0.)
        {
            QTimer::singleShot(50,this,&FadingImagesPushButton::hoverEnter);
        }
    }
    else
        QTimer::singleShot(0,this,&FadingImagesPushButton::hoverLeave);
}

void FadingImagesPushButton::hoverLeave()
{
    if(toHoverTimer.elapsed() > s_AnimDuration)
    {
        m_currentOpacity = (float)toNormalTimer.elapsed() / (float)s_AnimDuration;
        if(m_currentOpacity > 1.)
            m_currentOpacity = 1.;
        applyComposition();
        if(m_currentOpacity < 1.)
        {
            QTimer::singleShot(50,this,&FadingImagesPushButton::hoverLeave);
        }
    }
    else
        QTimer::singleShot(0,this,&FadingImagesPushButton::hoverEnter);
}

void FadingImagesPushButton::applyComposition()
{
    QImage result = m_hoverLayer.convertToFormat(QImage::Format_ARGB32);
    QPixmap mask(result.size());
    QPainter painterOpacity(&result);
    painterOpacity.setCompositionMode(QPainter::CompositionMode_DestinationOut);
    painterOpacity.setOpacity(m_currentOpacity);
    painterOpacity.drawPixmap(0,0,mask);
    painterOpacity.end();

    QPainter composition(&result);
    composition.setCompositionMode(QPainter::CompositionMode_DestinationOver);
    composition.drawImage(0,0,m_normalImage);

    setIcon(QIcon(QPixmap::fromImage(result)));
}

相关问题