1.效果图
2.实现原理
这里做了两个widget,一个是 展示底图widget,一个是 展示动画widget。
这两个widget需要重合。动画widget需要设置属性叠加到底图widget上面,设置如下属性:
setWindowFlags(Qt::FramelessWindowHint | Qt::SubWindow | Qt::WindowStaysOnTopHint);
动画widget背景需要做成透明,我在上面放了一个QFrame,然后设置style:
QFrame#frame
{
background-color: rgba(255, 255, 255, 100);
}
动画widget上面放了一个QStackedWidget。一个用于显示 > 的图像,另一个则显示菜单。
动画效果:QPropertyAnimation类提供动画支持,改变geometry属性。
m_slideOutAnimation = new QPropertyAnimation(this,"geometry");
connect(m_slideOutAnimation,&QPropertyAnimation::finished,this,&SlideAnimationWidget::slotSlideOutFinished);
m_slideOutAnimation->setEasingCurve(QEasingCurve::OutSine);
m_slideOutAnimation->setDuration(1300);
m_slideInAnimation = new QPropertyAnimation(this,"geometry");
connect(m_slideInAnimation,&QPropertyAnimation::finished,this,&SlideAnimationWidget::slotSlideInFinished);
m_slideInAnimation->setEasingCurve(QEasingCurve::InSine);
m_slideInAnimation->setDuration(1300);
最后安装事件过滤器:通过鼠标进入和离开事件,触发动画效果。
ui->label->installEventFilter(this);
ui->controlWidget->installEventFilter(this);
3.源码
#ifndef SLIDEANIMATIONWIDGET_H
#define SLIDEANIMATIONWIDGET_H
#include <QWidget>
#include <QPropertyAnimation>
#include <QEvent>
#include <QRect>
namespace Ui {
class SlideAnimationWidget;
}
#define SLIDE_MIN_WIDTH 10 //侧边栏滑出最小的宽度
#define SLIDE_MAX_WIDTH 300 //侧边栏滑出最大的宽度
class SlideAnimationWidget : public QWidget
{
Q_OBJECT
public:
explicit SlideAnimationWidget(QWidget *parent = 0);
~SlideAnimationWidget();
public:
void setPos(int x,int y);
protected:
bool eventFilter(QObject *obj, QEvent *event);
private slots:
void slotSlideOutFinished();
void slotSlideInFinished();
private:
Ui::SlideAnimationWidget *ui;
private:
QPropertyAnimation *m_slideOutAnimation = nullptr;
QPropertyAnimation *m_slideInAnimation = nullptr;
bool m_bShowSideflag = false; //显示侧边栏
bool m_bInComboBox = false;
int m_posX = 0;
int m_posY = 0;
bool m_isInit = false;
};
#endif // SLIDEANIMATIONWIDGET_H
#include "SlideAnimationWidget.h"
#include "ui_SlideAnimationWidget.h"
#include <QAbstractItemView>
#include <QListView>
#include <QMouseEvent>
SlideAnimationWidget::SlideAnimationWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::SlideAnimationWidget)
{
ui->setupUi(this);
setWindowFlags(Qt::FramelessWindowHint | Qt::SubWindow | Qt::WindowStaysOnTopHint);
m_slideOutAnimation = new QPropertyAnimation(this,"geometry");
connect(m_slideOutAnimation,&QPropertyAnimation::finished,this,&SlideAnimationWidget::slotSlideOutFinished);
m_slideOutAnimation->setEasingCurve(QEasingCurve::OutSine);
m_slideOutAnimation->setDuration(1300);
m_slideInAnimation = new QPropertyAnimation(this,"geometry");
connect(m_slideInAnimation,&QPropertyAnimation::finished,this,&SlideAnimationWidget::slotSlideInFinished);
m_slideInAnimation->setEasingCurve(QEasingCurve::InSine);
m_slideInAnimation->setDuration(1300);
ui->stackedWidget->setCurrentIndex(0);
ui->label->installEventFilter(this);
ui->controlWidget->installEventFilter(this);
ui->cbxFocusMode->view()->installEventFilter(this);
ui->cbxField->view()->installEventFilter(this);
ui->cbxFocusStep->view()->installEventFilter(this);
this->setMaximumWidth(SLIDE_MIN_WIDTH);
}
SlideAnimationWidget::~SlideAnimationWidget()
{
delete ui;
}
void SlideAnimationWidget::setPos(int x, int y)
{
m_posX = x;
m_posY = y;
move(x,y);
}
bool SlideAnimationWidget::eventFilter(QObject *obj, QEvent *event)
{
if(obj == ui->cbxFocusMode->view() ||
obj == ui->cbxField->view() ||
obj == ui->cbxFocusStep->view())
{
if (event->type() == QEvent::FocusIn)
{
m_bInComboBox = true;
}
else if (event->type() == QEvent::FocusOut)
{
m_bInComboBox = false;
}
}
else if(obj == ui->label)
{
//鼠标进入的时候
if (event->type() == QEvent::Enter &&
ui->stackedWidget->currentIndex() == 0 &&
!m_bShowSideflag)
{
if(m_slideOutAnimation->state() == QAbstractAnimation::Running)
return true;
//qDebug()<<"Enter";
this->setMaximumWidth(SLIDE_MAX_WIDTH);
m_slideOutAnimation->setStartValue(QRect(m_posX,m_posY,SLIDE_MIN_WIDTH,this->height()));
m_slideOutAnimation->setEndValue(QRect(m_posX,m_posY,SLIDE_MAX_WIDTH,this->height()));
m_slideOutAnimation->start();
ui->stackedWidget->setCurrentIndex(1);
m_bShowSideflag = true;
return true;
}
return false;//别的事件会传给label对象
}
else if(obj == ui->controlWidget)
{
//鼠标离开的时候
if (event->type() == QEvent::Leave &&
ui->stackedWidget->currentIndex() == 1 &&
m_bShowSideflag && !m_bInComboBox)
{
if(m_slideInAnimation->state() == QAbstractAnimation::Running)
return true;
//qDebug()<<"Leave";
m_slideInAnimation->setStartValue(QRect(m_posX,m_posY,SLIDE_MAX_WIDTH,this->height()));
m_slideInAnimation->setEndValue(QRect(m_posX,m_posY,SLIDE_MIN_WIDTH,this->height()));
m_slideInAnimation->start();
m_bShowSideflag = false;
return true;
}
return false;//别的事件会传给label对象
}
// standard event processing
return QWidget::eventFilter(obj, event);
}
void SlideAnimationWidget::slotSlideOutFinished()
{
}
void SlideAnimationWidget::slotSlideInFinished()
{
this->setMaximumWidth(SLIDE_MIN_WIDTH);
ui->stackedWidget->setCurrentIndex(0);
}
使用:新建一个MainWidget,将m_animationWidget父对象设置为this。
做了一个void MainWidget::resizeEvent(QResizeEvent *event)事件,根据MainWidget的尺寸,自适应m_animationWidget的高度。
#include "MainWidget.h"
#include "ui_MainWidget.h"
#include "SlideAnimationWidget.h"
#include <QDebug>
#define POS_X 5
#define POS_Y 26
MainWidget::MainWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::MainWidget)
{
ui->setupUi(this);
m_animationWidget = new SlideAnimationWidget(this);
m_animationWidget->setPos(POS_X,POS_Y);
}
MainWidget::~MainWidget()
{
delete ui;
}
void MainWidget::resizeEvent(QResizeEvent *event)
{
m_animationWidget->setFixedHeight(event->size().height()-POS_Y*2);
}
void MainWidget::showEvent(QShowEvent *event)
{
Q_UNUSED(event);
if(m_isInit)
return;
setWindowState(Qt::WindowFullScreen);
showMaximized();
m_isInit = true;
}
4.相关参考
Qt 事件过滤器(秒懂)_qt事件过滤器-CSDN博客
Qt 事件处理机制简介_qt获取事件的发起者_Mr.codeee的博客-CSDN博客
Qt 自定义悬浮窗(带动画,类似QQ拼音输入法)_qt 浮动窗口设置悬浮-CSDN博客