提示弹窗在GUI中比较常用的有QMessageBox或自定义Widget,但是这些会挡住当前页面并且要手动关闭,非常不方便,于是本文介绍了一种不阻塞线程的弹窗动画,可以自动消失
主要逻辑为自定义一个按钮,通过动画来实现上下移动,根据字符长度改变按钮的大小
1.自定义一个MySnackBar类,通过qt动画来实现
MySnackBar.h
#ifndef MYSNACKBAR_H
#define MYSNACKBAR_H
#include <QWidget>
#include <QPropertyAnimation>
#include <QParallelAnimationGroup>
#include <QSequentialAnimationGroup>
#include <QGraphicsOpacityEffect>
#include <QPushButton>
class MySnackbar : public QWidget
{
Q_OBJECT
public:
MySnackbar(QWidget *parent = nullptr);
~MySnackbar();
void initAnimation();
void setSnackbarStyleSheet(const QString & message_str);
void setDuration(int stay_time);//500ms
public slots:
void showMessage(const QString & message_str,int y=0);
void showMessage(const QString & message_str, bool isSucc,int y=0);
private:
QParallelAnimationGroup *m_group;
QPushButton *m_pbtn_ptr;
QPropertyAnimation *pPos_start_Animation ;
QPauseAnimation *pPause_Animation;
QPropertyAnimation *pPos_back_Animation;
QSequentialAnimationGroup *pPosGroup ;
private:
QWidget *parent_widget;
};
#endif // MYSNACKBAR_H
2.初始化动画
void MySnackbar::initAnimation() {
int snack_width = 200; // 计算按钮的宽度
int snack_height = 70; // 计算按钮的高度
setWindowFlags(Qt::FramelessWindowHint); // 设置窗口为无边框
// 上升动画
pPos_start_Animation = new QPropertyAnimation(this, "pos"); // 创建位置属性动画对象
pPos_start_Animation->setDuration(500); // 500毫秒
pPos_start_Animation->setEasingCurve(QEasingCurve::InOutQuad); // 设置动画缓动曲线
// 悬停动画
pPause_Animation = new QPauseAnimation(1000); // 创建暂停动画对象,持续时间为1000毫秒
// 下降动画
pPos_back_Animation = new QPropertyAnimation(this, "pos"); // 创建位置属性动画对象
pPos_back_Animation->setDuration(500); // 500毫秒
pPos_back_Animation->setEasingCurve(QEasingCurve::InOutQuad); // 设置动画缓动曲线
pPosGroup = new QSequentialAnimationGroup(this); // 创建顺序动画组对象
// pPosGroup->addPause(500); // 可选的暂停动画,暂停时间为500毫秒
pPosGroup->addAnimation(pPos_start_Animation); // 将上升动画添加到顺序动画组
pPosGroup->addAnimation(pPause_Animation); // 将悬停动画添加到顺序动画组
pPosGroup->addAnimation(pPos_back_Animation); // 将下降动画添加到顺序动画组
m_group = new QParallelAnimationGroup(this); // 创建并行动画组对象
m_group->addAnimation(pPosGroup); // 将顺序动画组添加到并行动画组
m_pbtn_ptr = new QPushButton(this); // 创建按钮对象
m_pbtn_ptr->setFixedSize(snack_width - 10, snack_height); // 设置按钮大小
QHBoxLayout* box_ptr = new QHBoxLayout(this); // 创建水平布局对象
box_ptr->setContentsMargins(0,0,0,0); // 设置布局边距
box_ptr->addWidget(m_pbtn_ptr); // 将按钮添加到布局中
// 动画结束后隐藏控件
connect(m_group, &QParallelAnimationGroup::finished, this, [this]() {
this->hide(); // 隐藏控件
});
}
3.封装设置样式以及动画延时时间的函数
void MySnackbar::setSnackbarStyleSheet(const QString& message_str) { m_pbtn_ptr->setStyleSheet(message_str); }
void MySnackbar::setDuration(int stay_time) { pPause_Animation->setDuration(stay_time); }
4. 显示动画,根据字符长度,动态改变弹窗的大小
void MySnackbar::showMessage(const QString& message_str,int y) {
m_group->stop();
m_pbtn_ptr->setText(message_str);
int str_size = (message_str.size() *7);//根据字符串长度动态调整
if (parent_widget) {
QRect parentGeometry = parent_widget->geometry(); // 获取父窗口的位置和大小
int parentWidth = parentGeometry.width(); // 获取父窗口的宽度
int parentHeight = parentGeometry.height(); // 获取父窗口的高度
int snack_width = 200; // 按钮的宽度
int snack_height = 70; // 按钮的高度
this->setFixedSize(snack_width + str_size, snack_height);
m_pbtn_ptr->setFixedSize(snack_width - 10 + str_size, snack_height - 10);
QFont font = m_pbtn_ptr->font();
int fontSize = m_pbtn_ptr->font().pointSize()*newAdjFontScale;
if(fontSize>0) font.setPointSize(fontSize);
m_pbtn_ptr->setFont(font);
int start_x = (parentWidth - this->width()) / 2;
int start_y = parentHeight-y;
pPos_start_Animation->setStartValue(QPoint(start_x, start_y));
pPos_start_Animation->setEndValue(QPoint(start_x, start_y - this->height()));
pPos_back_Animation->setStartValue(QPoint(start_x, start_y - this->height()));
pPos_back_Animation->setEndValue(QPoint(start_x, start_y));
this->move(start_x, start_y);
show();
m_group->setDirection(QAbstractAnimation::Forward); // 设置动画播放方向为正向
m_group->setLoopCount(1); // 设置动画循环次数为1次
m_group->start(); // 启动动画
}
}
5.封装一个接口方便使用
void MySnackbar::showMessage(const QString &message_str, bool isSucc,int y)
{
if (isSucc)
setSnackbarStyleSheet("QPushButton{background-color:rgb(85,188,179);color:white;border-radius:10px;font-family:Microsoft YaHei;font:bold 18px;}");
else
setSnackbarStyleSheet("QPushButton{background-color:rgb(255,0,0);color:white;border-radius:10px;font-family:Microsoft YaHei;font:bold 18px;}");
showMessage(message_str,y);
}
6.使用方法以及效果
snackBar = new MySnackbar(this);
snackBar->showMessage(msg, isSucc);