Qt 实现侧边栏滑出菜单效果

news2024/11/19 18:45:12

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博客 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1138106.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023/10/26MySQL学习

事务 询问当前是什么提交方式 1代表默认提交,0代表手动提交 将事务设为手动提交 将事务设置为手动提交后,mysql语句只会执行,但不会对原本表中数据进行更改, 只有执行以下两个语句之一,才会继续进行 commit完成原本操作,更改数据 rollback取消原来事务,不会进行任何更改 如…

【嵌入式Linux】编译应用和ko内核模块Makefile使用记录

文章目录 一、常用的语法1.1 , :, , ?的区别1.2 命名模式&#xff1a;target-objs 和 target-y 的区别 二、编译KO2.1 难度0&#xff1a;一个.c文件编译成一个.ko文件2.1.1 改进一下Makefile使得编译命令只需要make就可以 2.2 难度1&#xff1a;多个.c,.h文件编译成一个.ko文件…

在Java中使用FileReader.read()进行读取文件时,为什么乱码?两个方法解决

public class FileReader_ {public static void main(String[] args) {}Testpublic void m1() {String filePath "e:\\hello.txt";FileReader fileReader null;try {fileReader new FileReader(filePath);//循环读取 使用readwhile (fileReader.read()!-1){System…

使用dlib,OpenCV和Python进行人脸识别—人眼瞌睡识别

前期文章我们分享了如何使用python与dlib来进行人脸识别,以及来进行人脸部分的识别, 如下图,dlib人脸数据把人脸分成了68个数据点,从图片可以看出,人脸识别主要是识别:人眉,人眼,人鼻,人嘴以及人脸下颚边框,每个人脸的部位都有不同的数据标签从1-68 当我们识别出人脸…

伦敦银现货白银走势如何应对

伦敦银是国际现货白银交易的别称&#xff0c;它每天的价格走势受到全球投资者广泛的关注&#xff0c;也是全球各个白银市场的价格指标。白银投资者要了解伦敦银走势的特点&#xff0c;才能更好地进行分析&#xff0c;实现自己的所预期的收益。 整体来说&#xff0c;伦敦银价格的…

Java工具库——Hutool的50个常用方法

爱一辈子也好&#xff0c;恨一辈子也罢&#xff0c;终究是要让你记我一辈子… 工具库介绍 Hutool-All&#xff08;或简称Hutool&#xff09;是一个功能强大的Java编程工具库&#xff0c;旨在简化Java应用程序的开发。它提供了大量的工具类和方法&#xff0c;涵盖了各种常见任务…

创建个人github.io主页(基础版)//吐槽:很多国内教程已经失效了

一、就跟着官网教程来很快就好了 官方文档的教程 GitHub Pages | Websites for you and your projects, hosted directly from your GitHub repository. Just edit, push, and your changes are live. // 简单跑通为例&#xff0c;第一个链接直接能行了&#xff0c;如果不想…

数据泄露高达7 TB ,这家医疗巨头数据库无任何密码保护

该数据库由Redcliffe Labs拥有&#xff0c;Redcliffe Labs是一家位于北方邦诺伊达的印度医疗公司。 网络安全研究员杰里迈亚-福勒&#xff08;Jeremiah Fowler&#xff09;发现了一个无密码保护的数据库&#xff0c;其中包含 1200 多万条记录。这些数据包括敏感的患者数据&…

本地存储 sessionStoragelocalStorage

随着互联网的快速发展&#xff0c;基于网页的应用越来越普遍&#xff0c;同时也变的越来越复杂&#xff0c;为了满足各种各样的需求&#xff0c;会经常性在本地存储大量的数据&#xff0c;HTML5规范提出了相关解决方案。 本地存储特性 数据存储在用户浏览器中 设置、读取方便、…

自监督学习应用

1 自监督学习 自监督学习主要是利用辅助任务&#xff08;pretext&#xff09;从大规模的无监督数据中挖掘自身的监督信息&#xff0c;通过这种构造的监督信息对网络进行训练&#xff0c;从而可以学习到对下游任务有价值的表征。&#xff08;也就是说自监督学习的监督信息不是人…

涨幅25%,2023全球电动车销量将飙升至2000万辆 | 百能云芯

近日&#xff0c;工研院在「眺望2024产业发展趋势研讨会」上发布消息&#xff0c;预测随着全球晶片短缺的逐渐缓解&#xff0c;以及俄乌地区供应链产能向其他国家的部分转移&#xff0c;全球汽车市场在疫情的影响下逐渐回暖。根据工研院的数据&#xff0c;2023年全球汽车销量预…

DSP_控制程序框架有感

本文仅代表个人观点&#xff0c;若有不同意见&#xff0c;请评论区讨论或私信留言。 中心思想&#xff1a; 基于DSP的控制程序可分为两个部分&#xff0c;① 对实时性要求高的部分&#xff0c;②对实时性要求不高的部分。 ① 对实时性要求高的程序&#xff0c;建议采用中断处理…

Ubuntu22.04本地部署PaddleSpeech实验代码(GPU版)

前言 之前做了一个Ubuntu18.04.6本地部署PaddleSpeech实验代码&#xff08;CPU版&#xff09;的相关项目&#xff0c;因为是CPU版的&#xff0c;合成/训练等方面的耗时真的是非常感人&#xff0c;有了之前的经验&#xff0c;又部署了一个GPU版的&#xff0c;说实话虽然时间用的…

CVE-2022-22963 Spring Cloud Function SpEL命令注入

一、简介 Spring Cloud Function 是基于 Spring Boot的函数计算框架。该项目致力于促进函数为主的开发单元&#xff0c;它抽象出所有传输细节和基础架构&#xff0c;并提供一个通用的模型&#xff0c;用于在各种平台上部署基于函数的软件。在Spring Cloud Function相关版本&am…

Pytest框架之fixture详解

本文详细讲解了Pytest框架之fixture&#xff0c;文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值&#xff0c;需要的朋友可以参考下 相关文章 pytest作为python语言的测试框架&#xff0c;它的fixture有2种实现方式。 一种是xunit-style&#xf…

OpenLayers实战,OpenLayers获取用户定位位置并高亮显示用户所在行政区划边界

专栏目录: OpenLayers实战进阶专栏目录 前言 本篇文章通过国内的省、自治区和直辖市的GeoJson数据作为行政区划边界数据,然后根据用户定位位置,通过OpenLayers计算得到用户所在行政区划,并使用OpenLayers高亮显示用户所在行政区划边界。 本章是综合应用场景,所以代码稍…

ESP32 ESP-IDF LVGL移植和Wokwi仿真

陈拓 2023/10/21-2023/10/25 1. ESP-IDF开发环境 ESP-IDF的LVGL移植包括2个组件&#xff1a; lvgllvgl_esp32_drivers 目前lvgl_esp32_drivers在ESP-IDF 5.0以上版本编译通不过&#xff0c;所以我们安装ESP-IDF 4.4.5。 从https://dl.espressif.cn/dl/esp-idf/下载 安装说明…

纳米软件分享:芯片电学测试及测试参数指标介绍

电学测试是芯片测试的一个重要环节&#xff0c;用来描述和评估芯片的电性能、稳定性和可靠性。芯片电学测试包括直流参数测试、交流参数测试和高速数字信号性能测试等。 什么是芯片电学测试? 芯片电学测试就是检测芯片、元件等电性能参数是否满足设计的要求。检测的项目有电压…

【uniapp】短信验证码输入框

需求是短信验证码需要格子输入框 如图 网上找了一个案例改吧改吧 直接上代码 结构 <template><view class"verify-code"><!-- 输入框 --><input id"input" :value"code" class"input" :focus"isFocus"…

Ubuntu安装Jitsi Meet详细教程

文章目录 Ubutu系统安装启用root账户切换Ubuntu源设置DNS 主机名和域名配置安装open JDK安装Nginx安装 Jitsi Meetjitsi本地测试使用一个奇怪的BUG Jist服务管理 Ubutu系统安装 官方推荐用Ubuntu&#xff0c;网上很多教程也都是基于Ubuntu的&#xff0c;所以选择这个系统。 其…