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_OBJECTpublic: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 processingreturn 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 26MainWidget::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博客