Qt QWidget 隐藏动画

3
我有一个继承自QWidget的子类,它是一个弹出窗口小部件。我想在显示和消失时添加一些动画效果。因此,我重新实现了showEvent(QShowEvent * event)hideEvent,并在这些函数中添加了一些QPropertyAnimation。对于showEvent,它对我来说完全正常,但hideEvent不起作用。因为

隐藏事件在小部件被隐藏后立即发送。

你有什么想法吗?

更新:

我不认为这是正确的原因。当我使用Nejat的解决方案时,显示部分有效。但是当我单击窗口小部件外部时,它会立即消失。

2个回答

2

您应该重载 QWidget::closeEvent() 方法,这样当试图立即关闭窗口时,它将被忽略,并且我们会启动我们的动画,在完成后 (QPropertyAnimation::finished()) 正常关闭小部件。

这里是一个演示:

class AnimatedWidget : public QWidget {
    Q_OBJECT
        Q_PROPERTY(qreal alpha READ alpha WRITE setAlpha)

public:
    AnimatedWidget(QWidget* parent = nullptr) :QWidget{ parent }, opacityAnimation{ new QPropertyAnimation{this, "alpha",this} } {
        setWindowFlags(windowFlags() | Qt::WindowFlags(Qt::FramelessWindowHint) | Qt::Tool);
        auto pal = palette();
        pal.setColor(QPalette::Background, Qt::cyan);
        setAutoFillBackground(true);
        setPalette(pal);
        setFixedSize(200, 200);
    }

    qreal alpha() const {
        return windowOpacity();
    }

    void setAlpha(qreal level) {
        setWindowOpacity(level);
        update();
    }

protected:
    void closeEvent(QCloseEvent* e) override {
        if (opacityAnimation->currentValue().toReal() == 1.0) { // Ignore event + start animation
            e->ignore();
            startHide();
            QObject::connect(opacityAnimation, SIGNAL(finished()), this, SLOT(onAnimationCallBack()), Qt::UniqueConnection);
        } else {
            e->accept();
            if (!isHidden())
                hide();
            QWidget::close(); // necessary actions
        }
    }

    public Q_SLOTS:
    void show() {
        startShow();
        QWidget::show(); // necessary actions
    }

    private Q_SLOTS:
    void onAnimationCallBack() {
        if (opacityAnimation->currentValue().toReal() == 0.0) { // we're finished so let's really close the widget
            QCloseEvent ev;
            QApplication::sendEvent(this, &ev);
            qApp->sendEvent(this, &ev);
        }
    }

    void startHide() {
        opacityAnimation->setStartValue(1.0);
        opacityAnimation->setEndValue(0.0);
        opacityAnimation->setDuration(1500);
        opacityAnimation->start();
    }

    void startShow() {
        opacityAnimation->setStartValue(0.0);
        opacityAnimation->setEndValue(1.0);
        opacityAnimation->setDuration(1500);
        opacityAnimation->start();
    }

private:
    QPropertyAnimation* opacityAnimation = nullptr;
};

class Base : public QWidget {
public:
    Base(QWidget* parent = nullptr) :QWidget{ parent }, widget{ new AnimatedWidget{} } {

    }

private:
    AnimatedWidget* widget;

protected:
    void mouseReleaseEvent(QMouseEvent* e) override {
        if (widget->isHidden())
            widget->show();
        else
            widget->close();
        QWidget::mouseReleaseEvent(e);
    }
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    Base base;
    base.show();
    return app.exec();
}

enter image description here


谢谢你的回答。但是已经过了很长时间,我现在无法测试它。如果你得到了一些赞,我会将其标记为被接受的答案,以便帮助其他遇到同样问题的人。 - Mike Shaw

1
你可以在你的小部件中重写 eventFilter 并检查 QEvent::ShowQEvent::Close 事件。
bool MyWidget::eventFilter(QObject * obj, QEvent * event)
{
    if(obj == this && event->type() == QEvent::Show)
    {
        //about to show
    }
    else if(obj == this && event->type() == QEvent::Close)
    {
        //about to close
    }


    return false;
}

你还应该在构造函数中安装事件过滤器:

this->installEventFilter(this);

它的工作效果不好。显示部分没有问题。也许我找错了原因。当我点击小部件外面时,它会立即消失。 - Mike Shaw

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接