如何使 Qt 小部件淡入或淡出?

Posted

技术标签:

【中文标题】如何使 Qt 小部件淡入或淡出?【英文标题】:How to make Qt widgets fade in or fade out? 【发布时间】:2013-10-05 22:31:40 【问题描述】:

我正在尝试淡入和淡出QLabel 或任何QWidget 子类。我试过QGraphicsEffect,但不幸的是它只在Windows上运行良好,在Mac上不行。

唯一可以同时在 Mac 和 Windows 上运行的其他解决方案似乎有我自己的自定义 paintEvent,我在其中设置了 QPainter 的不透明度,并在派生的 @987654327 中为“不透明度”定义了一个 Q_PROPERTY @ 并通过QPropertyAnimation 更改不透明度。

我在下面贴上相关代码sn-p,供大家参考。我在这里仍然看到一个问题 - 重用 QLabel::paintEvent 似乎不起作用,它只有在我使用 QPainter 进行完整的自定义绘画时才有效,但这似乎不是一个简单的方法,如果我需要为我想要淡出的每个QWidget 子类执行此操作,这是一场噩梦。请澄清我是否在这里犯了任何明显的错误。

Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity)

void MyLabel::setOpacity(qreal value) 
    m_Opacity = value;
    repaint();


void MyLabel::paintEvent((QPaintEvent *pe) 
    QPainter p;
    p.begin(this);
    p.setOpacity();
    QLabel::paintEvent(pe);
    p.end();


void MyLabel::startFadeOutAnimation() 
    QPropertyAnimation *anim = new QPropertyAnimation(this, "opacity");
    anim->setDuration(800);
    anim->setStartValue(1.0);
    anim->setEndValue(0.0);
    anim->setEasingCurve(QEasingCurve::OutQuad);
    anim->start(QAbstractAnimation::DeleteWhenStopped);

【问题讨论】:

Qt API 告诉您,您正在以一种不应该被使用的方式使用它。当您想要像这样为它们的内容制作动画时,小部件并不是真正的出色表现者。它可能适用于概念验证,但从长远来看,您应该使用 Qt Quick。无论您使用 Qt Quick 1 还是 Qt Quick 2 都取决于您,即使是 Qt Quick 1(声明性模块)也会比您正在做的事情有所改进。 【参考方案1】:

很抱歉我不能用 C++ 编写它,但是在 python3 和 C++ 中的实现是一样的:

您可以创建一个 QVariantAnimation 动画代表不透明度的浮点值,将valueChanged 信号连接到自定义函数:

anim = QVariantAnimation()
anim.setStartValue(.3)
anim.setEndValue(.6)
anim.setDuration(900)
anim.setEasingCurve(QEasingCurve.InOutQuad) # Not strictly required, just for the aesthetics
anim.valueChanged.connect(lambda opacity: mySpecialFun(opacity))
anim.start()

然后,定义改变不透明度(或你想要动画的属性)的自定义函数:

def mySpecialFun(opacity: float) -> None:
    mywidget.setStyleSheet(f"background-color: rgba(0, 0, 0, color);")

这样做的原因是我们没有为属性设置动画。相反,我们正在为浮点值设置动画,但关键是每次浮点值更改时,我们都会获取它的值并将其传递给执行自定义工作的自定义函数(在我们的例子中,通过样式表设置不透明度)

【讨论】:

【参考方案2】:

实际上有一种超级简单的方法可以做到这一点,无需混乱的QPaintEvent 拦截,也无需QGraphicsProxyWidget 的严格要求,这不适用于提升的小部件子级。下面的技术甚至适用于提升的小部件及其子小部件。

淡入你的小部件

// w is your widget
QGraphicsOpacityEffect *eff = new QGraphicsOpacityEffect(this);
w->setGraphicsEffect(eff);
QPropertyAnimation *a = new QPropertyAnimation(eff,"opacity");
a->setDuration(350);
a->setStartValue(0);
a->setEndValue(1);
a->setEasingCurve(QEasingCurve::InBack);
a->start(QPropertyAnimation::DeleteWhenStopped);

淡出你的小部件

// w is your widget
QGraphicsOpacityEffect *eff = new QGraphicsOpacityEffect(this);
w->setGraphicsEffect(eff);
QPropertyAnimation *a = new QPropertyAnimation(eff,"opacity");
a->setDuration(350);
a->setStartValue(1);
a->setEndValue(0);
a->setEasingCurve(QEasingCurve::OutBack);
a->start(QPropertyAnimation::DeleteWhenStopped);
connect(a,SIGNAL(finished()),this,SLOT(hideThisWidget()));
// now implement a slot called hideThisWidget() to do
// things like hide any background dimmer, etc.

【讨论】:

我真的很喜欢这个答案!虽然,是否有一种简单的方法可以淡入/淡出多个小部件? 重要如果在 python 中运行此代码,您需要保存 aeff 变量 (self.a=),这样它们就不会被垃圾收集 【参考方案3】:

尝试将调色板的某些部分作为标签的属性,然后对其进行动画处理:

Q_PROPERTY(QColor color READ color WRITE setColor)

void MyLabel::setColor(const QColor &value) 
    QPalette palette;
    palette.setBrush(QPalette::WindowText, value);
    setPalette(palette);


QColor MyLabel::color() 
    return palette(QPalette::Normal, QPalette::Window).


void MyLabel::startFadeOutAnimation() 
    QPropertyAnimation *animation = new QPropertyAnimation(label, "color", this);
    QColor c = label->color();
    animation->setKeyValueAt(0, c);
    c.setAlpha(0);
    animation->setKeyValueAt(1, c);
    animation->setEasingCurve(QEasingCurve::OutQuad);
    animation->setDuration(1000);
    animation->start(QAbstractAnimation::DeleteWhenStopped);

您可以通过定义和注册新的插值器来尝试避免子类化,该插值器将处理 QPalette qRegisterAnimationInterpolator,但这有点复杂。

【讨论】:

【参考方案4】:

您可以将小部件放入QGraphicsScene。它支持不透明度变化和动画。

有关示例,请参阅 QGraphicsProxyWidget 文档。

【讨论】:

以上是关于如何使 Qt 小部件淡入或淡出?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Qt 中将动画用于堆叠的小部件?

在 Gtk 中,是不是可以让小部件淡入淡出?

Flutter-当内容更改时淡入淡出动画文本小部件

如何使布局填充qt选项卡小部件内的所有内容?

如何在Qt Creator中使两个小部件相互连接并相互调整大小[重复]

如何为 StreamBuilder 生成的小部件设置动画?