C++复刻:[滑动侧边栏]

news2024/9/23 11:21:08

目录

  • 参考
  • 效果
  • 实现
    • main.cpp
    • widget.h
    • widget.cpp
    • custombtn.h 自定义按钮
    • custombtn.cpp 自定义按钮
    • slidingSideWindow.h 滑动侧边栏
    • slidingSideWindow.cpp 滑动侧边栏
  • 模糊知识点
  • 源码

参考

Python版本:GitHub地址
B站主页

效果

在这里插入图片描述

实现

main.cpp

#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    widget w;
    w.show();
    return a.exec();
}

widget.h

widget.cpp

#include "widget.h"
#include "slidingSideWindow.h"
#include <QDebug>
widget::widget(QWidget *parent)
    : QWidget{parent}
{
    this->resize(800,600);
    this->setWindowFlag(Qt::WindowStaysOnTopHint);
    //线性渐变
    setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, "
                  "stop:0 #e60042, stop:0.05 #d40f52, stop:0.20 #c21d62, stop:0.31 #af2c72, "
                  "stop:0.45 #7958a3, stop:0.79 #8b4993, stop:0.86 #6667b3, stop:0.935 #5475c3);");
    auto pSideWindow=new SlidingSideWindow(this);
    pSideWindow->move(this->rect().center().x()-pSideWindow->width()/2,
                      this->rect().center().y()-pSideWindow->height()/2);
    qDebug()<<__FUNCTION__<<" :x ="<<this->rect().center().x()-pSideWindow->width()/2;
    qDebug()<<__FUNCTION__<<" :y ="<<this->rect().center().y()-pSideWindow->height()/2;
}

widget::~widget()
{

}

custombtn.h 自定义按钮

#ifndef CUSTOMBTN_H
#define CUSTOMBTN_H

#include <QFrame>
#include <QObject>
#include <QPushButton>
#include <QPropertyAnimation>
#include <QPainter>
#include <QPainterPath>

class customBtn : public QFrame
{
    Q_OBJECT
    /* 将m_color属性声明为可用于属性系统的属性。然后,提供了一个getColor函数作为该属性的读取器,
     * 以及一个setColor函数作为写入器。
     *  在setColor函数中,我们可以执行一些自定义逻辑,并在属性值发生变化时进行处理。 */
    Q_PROPERTY(QColor m_color READ getColor WRITE setColor)
    Q_PROPERTY(QSize m_size READ getSize WRITE setSize)
public:
    customBtn(QWidget *parent = nullptr, QString text = "", QString iconFile = "");
    ~customBtn();
    QColor getColor() const { return m_color; }
    void setColor(const QColor& color);
    QSize getSize() const { return m_size; }
    void setSize(const QSize& color);
    QPushButton *pushButton(){return m_pPushButtonRight;}
    int getWidth(){return this->width();}
    int getHeight(){return this->height();}
protected:
    void paintEvent(QPaintEvent *event) override;
    void enterEvent(QEvent *event) override ;
    void leaveEvent(QEvent *event) override ;
signals:
    void colorChanged();            //响应m_color属性动画
private slots:
    void updateColor();
private:
    QSize m_size;
    QColor  m_color;
    QString m_iconFile;
    QString m_btnText;
    QPropertyAnimation *m_pAnimation;  //属性动画
    QPushButton* m_pPushButtonIcon;
    QPushButton* m_pPushButtonRight;
    void initUI();
    void hoveringAnimation();           //鼠标悬停动画
};

#endif // CUSTOMBTN_H

custombtn.cpp 自定义按钮

#include "custombtn.h"
#include <QDebug>
customBtn::customBtn(QWidget *parent, QString text, QString iconFile)
    : QFrame(parent), m_color(QColor(255, 116, 0, 255)), m_iconFile(iconFile), m_btnText(text)
{
    this->initUI();
}

customBtn::~customBtn()
{

}

void customBtn::setColor(const QColor &color)
{
    if (m_color != color) {
        m_color = color;
        emit colorChanged();
    }
}

void customBtn::setSize(const QSize &size)
{
    if (m_size != size) {
        m_size = size;
        this->resize(size);
    }
}

void customBtn::hoveringAnimation()
{
    m_pAnimation->setTargetObject(this);        //动画的目标对象设置为当前对象
    m_pAnimation->setPropertyName("m_color");   //动画关联到属性m_color,这意味着动画将修改该属性的值来实现动画效果
    m_pAnimation->setDuration(300);             //动画的持续时间
    //动画的开始值和结束值
    m_pAnimation->setStartValue(QColor(255, 116, 0, 255));
    m_pAnimation->setEndValue(QColor(255, 116, 255, 225));
    m_pAnimation->start();
}

void customBtn::paintEvent(QPaintEvent *event)
{
    QFrame::paintEvent(event);

    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing); // 抗锯齿
    //设置画笔; Qt::NoPen 表示不使用画笔,也就是不绘制边框
    painter.setPen(Qt::NoPen);

    // 绘制圆角矩形背景
    QPainterPath path;
    path.addRoundedRect(this->rect(), 10, 10);
    painter.fillPath(path, m_color);
}

void customBtn::enterEvent(QEvent *event)
{
    // 设置动画的方向为正向
    m_pAnimation->setDirection(QAbstractAnimation::Forward);
    hoveringAnimation();
    QFrame::enterEvent(event);
}

void customBtn::leaveEvent(QEvent *event)
{
    //将动画设置为反向播放
    m_pAnimation->setDirection(QAbstractAnimation::Backward);
    this->hoveringAnimation();
    QFrame::leaveEvent(event);
}

void customBtn::updateColor()
{
    //按钮的背景颜色需要设置成透明,以便于绘制显示QFrame底色
    this->setStyleSheet(QString("QFrame{border-radius: 10px; background-color: rgba(255, 116, 200, 225);} "
                          "QPushButton{border-radius: 10px; background-color: transparent; color: rgb(255, 255, 255);}"));
    this->update();
}

void customBtn::initUI()
{
    this->resize(110, 30);
    this->setMinimumSize(40, 30);
    this->setMaximumSize(110, 30);
    m_size=this->size();
    //QFrame背景颜色和按钮的背景颜色一样,这样就看不见两个按钮之间的边框圆角
    this->setStyleSheet(QString("QFrame{border-radius: 10px; background-color: rgba(255, 116, 0, 255); color: rgb(255, 255, 255);} "
                          "QPushButton{border-radius: 10px; background-color: rgba(255, 116, 0, 255); color: rgb(255, 255, 255);}"));
    m_pPushButtonIcon = new QPushButton(this);
    m_pPushButtonIcon->setGeometry(QRect(0, 0, 30, 31));
    m_pPushButtonIcon->setStyleSheet("padding-left:10px");//设置左边内边距的大小
    QIcon icon(m_iconFile);
    m_pPushButtonIcon->setIcon(icon);
    m_pPushButtonIcon->setIconSize(QSize(20, 20));

    m_pPushButtonRight = new QPushButton(this);
    m_pPushButtonRight->setGeometry(QRect(30, 0, 80, 31));
    m_pPushButtonRight->setStyleSheet("padding-left:15px; text-align: left;");
    m_pPushButtonRight->setIconSize(QSize(20, 20));
    m_pPushButtonRight->setText(m_btnText);
    m_pPushButtonRight->setCheckable(true);
    connect(this,SIGNAL(colorChanged()), this, SLOT(updateColor()));

    m_pAnimation=new QPropertyAnimation(this);
}

slidingSideWindow.h 滑动侧边栏

#ifndef SLIDINGSIDEWINDOW_H
#define SLIDINGSIDEWINDOW_H

#include <QFrame>
#include <QPropertyAnimation>
#include <QAbstractAnimation>
#include <QParallelAnimationGroup>
#include <QPushButton>
#include "custombtn.h"


class SlidingSideWindow : public QFrame
{
    Q_OBJECT

public:
    SlidingSideWindow(QWidget *parent = nullptr);
    ~SlidingSideWindow();
protected:
    void enterEvent(QEvent *event) override;
    void leaveEvent(QEvent *event) override;
private:
    int m_widthHide;                //滑动侧边栏隐藏时宽度
    int m_widthShow;                //滑动侧边栏显示时宽度
    int m_widthChange;              //变化使用宽度
    int m_xShow;
    int m_xHide;
    int m_y;
    int m_customBtn_widthShow;
    int m_customBtn_widthHide;
    int m_customBtn_height;
    bool enterFlag;                 // 判断是否第一次进入
    QParallelAnimationGroup *animationGroup;//并行播放多个动画的动画组
    void initUI();
    void configInit();
    void animationGroupConfig();
    void anewRecordPos();            //重新记录位置
};

#endif // SLIDINGSIDEWINDOW_H

slidingSideWindow.cpp 滑动侧边栏


#include "slidingSideWindow.h"
#include <QDebug>
SlidingSideWindow::SlidingSideWindow(QWidget *parent)
    : QFrame(parent)
{
    initUI();
    configInit();
}

SlidingSideWindow::~SlidingSideWindow()
{
}

void SlidingSideWindow::enterEvent(QEvent *event)
{
    QFrame::enterEvent(event);
    // 跳过第一次
    if (!enterFlag)
    {
        enterFlag = true;
        /*因为new时 this->x()和y() 都是0; move之后才有值;只记录第一次进入this的Pos()*/
        anewRecordPos();            //重新记录位置
        return;
    }

    // 显示包含文字的按钮
    QList<customBtn *> frames = this->findChildren<customBtn *>();
    for (auto item : frames)
    {
        item->pushButton()->show();
    }

    animationGroup->setDirection(QAbstractAnimation::Backward);
    animationGroup->start();
}

void SlidingSideWindow::leaveEvent(QEvent *event)
{
    QFrame::leaveEvent(event);
    QList<customBtn *> frames = this->findChildren<customBtn *>();
    for (auto item : frames)
    {
        item->pushButton()->hide();
    }

    animationGroup->setDirection(QAbstractAnimation::Forward);
    animationGroup->start();
}


void SlidingSideWindow::initUI()
{
    this->resize(141, 271);
    this->setStyleSheet("QFrame{border-radius: 15px;"
            "background-color: rgba(255, 116, 0,200);}");
    // 判断是否第一次进入
    enterFlag = false;

    //并行播放多个动画的动画组
    animationGroup = new QParallelAnimationGroup(this);
}

void SlidingSideWindow::configInit()
{
    auto childFrame =new customBtn(this,"Close",":/icon/Close.png");
    childFrame->setGeometry(QRect(10, 20, 110, 30));
    auto childFrame_2 =new customBtn(this,"Enter",":/icon/Enter.png");
    childFrame_2->setGeometry(QRect(10, 60, 110, 30));
    auto childFrame_3 =new customBtn(this,"SetKey",":/icon/SetKey.png");
    childFrame_3->setGeometry(QRect(10, 100, 110, 30));
    auto childFrame_4 =new customBtn(this,"Resign",":/icon/Resign.png");
    childFrame_4->setGeometry(QRect(10, 140, 110, 30));
    auto childFrame_5 =new customBtn(this,"Verify",":/icon/Verify.png");
    childFrame_5->setGeometry(QRect(10, 180, 110, 30));
    auto childFrame_6 =new customBtn(this,"Share",":/icon/Share.png");
    childFrame_6->setGeometry(QRect(10, 220, 110, 30));
    m_customBtn_widthShow = childFrame->getWidth();
    m_customBtn_widthHide = 40;
    m_customBtn_height = childFrame->getHeight();

    anewRecordPos();            //重新记录位置
}

void SlidingSideWindow::animationGroupConfig()
{
    // 清空动画组
    animationGroup->clear();

    /*在leaveEvent和enterEvent中对右侧按钮隐藏后,通过QPropertyAnimation属性动画修改customBtn的
     *自定义属性m_size,以更改customBtn底下的QFrame大小。否则QFrame存在background-color就看不到
     *customBtn图标的右侧圆角*/
    // 按钮动画
    QList<customBtn *> frames = this->findChildren<customBtn *>();
    for (auto childFrame : frames)
    {
        QPropertyAnimation *btnAnimation = new QPropertyAnimation(childFrame, "m_size");
        btnAnimation->setDuration(150);
        btnAnimation->setStartValue(QSize(m_customBtn_widthShow, m_customBtn_height));
        btnAnimation->setEndValue(QSize(m_customBtn_widthHide, m_customBtn_height));
        animationGroup->addAnimation(btnAnimation);      // 添加属性动画到动画组
    }

    // 侧边栏动画
    QPropertyAnimation *frameAnimation = new QPropertyAnimation(this, "geometry");
    frameAnimation->setDuration(150);
    frameAnimation->setStartValue(QRect(m_xShow, m_y, m_widthShow, this->height()));
    frameAnimation->setEndValue(QRect(m_xHide, m_y, m_widthHide, this->height()));
    animationGroup->addAnimation(frameAnimation);         // 添加属性动画到动画组
}

//重新计算位置
void SlidingSideWindow::anewRecordPos()
{
    // 设置变形部件尺寸
    m_widthHide = 61;
    m_widthShow = this->width();
    m_widthChange = m_widthShow - m_widthHide;
    m_xShow = this->x();
    m_xHide = this->x() + m_widthChange / 2;
    m_y = this->y();

    animationGroupConfig();
}

模糊知识点

  1. QPropertyAnimation::setDirection(Direction )设置动画的播放方向
  2. Q_PROPERTY将成员变量(或者称为属性)公开为可由其他对象访问和操作的属性
Q_PROPERTY 宏的基本语法如下:
Q_PROPERTY(type name READ getterFunction [WRITE setterFunction] [RESET resetFunction]
               [NOTIFY notifySignal] [REVISION int]
               [DESIGNABLE bool] [SCRIPTABLE bool] [STORED bool]
               [USER bool] [CONSTANT] [FINAL])
其中,常用的属性选项包括:

type:属性的数据类型。
name:属性的名称。
READ getterFunction:返回属性值的函数。
WRITE setterFunction:设置属性值的函数(可选)。
NOTIFY notifySignal:当属性值发生变化时发出的信号(可选)。

源码

Gitee:07SlidingSideWindow滑动侧边栏

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

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

相关文章

K线与形态基础知识

一、单根K线的涨跌形态 实体&#xff1a;代表当日的股价涨跌幅大小&#xff0c;即波动大小&#xff0c;实体大&#xff0c;波动大。上影线&#xff1a;从实体向上延伸的即为上影线&#xff0c;表示股价上涨的轨迹&#xff0c;也是多方拉升意图的最佳表现&#xff0c;但是最终实…

Linux操作系统2-软件的安装

软件安装方式 二进制发布包安装 软件已针对具体平台编译打包&#xff0c;只需要解压、修改配置rpm安装 安装按照redhat的包管理规范进行打包&#xff0c;使用rpm命令进行安装&#xff0c;不能自行解决库依赖问题yum安装 一种在线软件安装方式&#xff0c;本质上还是rpm安装&am…

(14)Qt绘图(one)

目录 绘图的基本使用 绘图的流程 指定绘图设备的两种方式 QPen的使用 线条样式 笔帽样式 线条连接样式 QBrush的使用 画刷样式设置 Qt中的随机数的使用 填充规则 纹理填充&#xff08;图片填充&#xff09; 渐变填充 线性渐变 径向渐变 锥形渐变 渐变区域之外的…

EXCEL,vlookup以及数据去重

1&#xff0c;新建一个work表格&#xff0c;将数据copy进来&#xff0c;并做简单处理&#xff0c;让看起来舒服 2&#xff0c;使用vlookup函数查找数据是否在库中 注意:上图中的Table_array A1:C152&#xff0c;这个值要加绝对引用&#xff0c;写成&#xff1a; $A$1:$C$15…

深度学习环境配置pytorch-GPU版本

一、下载与安装Anaconda 官网&#xff1a;https://www.anaconda.com/download 安装时添加环境变量勾选上&#xff0c;这样可以减少一步操作&#xff0c;不用再去自己手动添加了。 二、在anaconda里面创建虚拟环境 创建虚拟环境&#xff0c;其中pytorch为虚拟环境名&#xff0c;…

解决Git下载失败太慢

解决Git下载失败太慢 Git 官网下载地址: https://git-scm.com/downloads Windows 下载地址: https://git-scm.com/download/win 用官网的地址下载, 需要从github上下载, 由于国内某些原因, 下载速度缓慢, 还经常失败. 国内用户, 可以通过镜像的方式, 提高下载速度. 阿里镜…

搭建工程化项目

搭建工程化项目 首先创建一个 study 空文件夹&#xff0c;并且把它拖到 VS Code 里面。 在 VS Code 中打开终端&#xff0c;快捷键 ctrl ~ 在命令行中输入 npm init&#xff0c;在接下来所有选项中全部按 “回车” 采用默认即可。 初始化完毕后&#xff0c;在项目根目录下会出…

SpringBoot集成jasypt,加密yml配置文件

SpringBoot集成jasypt&#xff0c;加密yml配置文件 一、pom配置二、生成密文代码三、配置3.1、yml加密配置3.2、密文配置3.3、启动配置3.4、部署配置 四、遇到的一些坑 最新项目安全检测&#xff0c;发现配置文件中数据库密码&#xff0c;redis密码仍处理明文状态 一、pom配置…

美团用户序列建模SDIM

Dimension Relation Modeling for Click-Through Rate Prediction 摘要 对于长期用户序列行为建模&#xff0c;采用两阶段方法&#xff0c;第一阶段检索出相关子序列&#xff0c;第二阶段应用注意力机制建模相关子序列和目标物料关系。基于检索的方式是次优的&#xff0c;可能…

MPDIoU: A Loss for Efficient and Accurate Bounding BoxRegression--论文学习笔记

超越GIoU/DIoU/CIoU/EIoU MPDIoU让YOLOv7和YOLACT双双涨点 目标检测上的指标对比&#xff1a; 论文地址&#xff1a; [2307.07662] MPDIoU: A Loss for Efficient and Accurate Bounding Box Regression (arxiv.org) 摘要 边界框回归&#xff08;Bounding Box Regression&am…

JSP项目国际化词条统计

国际化字条匹配并导出为excel格式 需求 将jsp页面里的key值&#xff0c;就是<spring:message code"gsyezer_Single_crystal"/>里的gsyezer_Single_crystal。和对应的字条对应上&#xff0c;并以excel表格形式输出。 jsp页面key值示例 <label for"&…

Redis 搭建主从集群

文章目录 1. 主从集群架构1.1 准备实例和配置1.2 启动1.3 开启主从关系1.4 测试 2. 主从同步原理2.1 全量同步2.2 增量同步repl_backlog原理 2.3 主从同步优化小结 单节点的 Redis 并发能力有限&#xff0c;要进一步提高 Redis 的并发能力&#xff0c;就需要搭建主从集群&#…

Eureka 学习笔记5:InstanceRegistry

版本 awsVersion ‘1.11.277’ LeaseManager 接口管理实例的租约信息&#xff0c;提供以下功能&#xff1a; 注册实例取消注册实例实例续约剔除过期实例 public interface LeaseManager<T> {/** 注册实例并续约*/void register(T r, int leaseDuration, boolean isRep…

8.1day02苍穹外卖开发

今天完善的功能是新增员工的功能&#xff1b; 新增员工需要添加的数据和员工表中的字段存在差异&#xff0c;用DTO封装传入进来的数据&#xff0c;将DTO实体的数据拷贝给employ类中去&#xff0c;采用的方式是用 BeanUtils.copyProperties(employeeDTO,employee); //前面是数据…

lodop学习

lodop 前提&#xff1a;为满足js调用打印机功能&#xff0c;浏览器自带的打印会弹出一个预览框&#xff0c;实际在应用场景上不需要这个预览弹窗&#xff0c;点击页面打印要直接根据预设好的参数直接打印&#xff0c;这个时候看到了lodop这个插件。 步骤1&#xff1a;官网下载…

一文搞懂Redis架构演化之路

目录 从最简单的开始&#xff1a;单机版 Redis 数据持久化&#xff1a;有备无患 主从复制&#xff1a;多副本 哨兵&#xff1a;故障自动切换 分片集群&#xff1a;横向扩展 总结 这篇文章我想和你聊一聊 Redis 的架构演化之路。 现如今 Redis 变得越来越流行&#xff0c;…

C++ ——stack、queue容器模拟实现及deque容器底层介绍

deque文档 stack文档 deque文档 文章目录 &#x1f345;1. deque容器&#x1f352;deque底层&#x1f352;deque的优势&#x1f352;deque的劣势 &#x1fad0;2. stack模拟实现&#x1f95d;3. queue模拟实现 &#x1f345;1. deque容器 查看文档可发现&#xff0c;栈和队列都…

前中后序迭代统一格式遍历法(最好理解)js版本

说实话,有关二叉树遍历这块,特别是迭代版本,网上好多写的糊里糊涂的,尤其是将三种遍历统一风格的,基本都是看到一头雾水,我想了个比较直观点(自认为) 首先,以下图二叉树为例, 使用迭代法,无论哪种遍历顺序都要首先要开一个栈,同时还需要一个指针cur用于控制当前 接…

Java三大特征之继承【超详细】

文章目录 一、继承概念二、继承的语法三、父类成员访问3.1子类中访问父类的成员变量3.2子类和父类成员变量同名3.3子类中访问父类的成员方法 四、super关键字五、子类构造方法六、super和this七、再谈初始化八、protected 关键字九、继承方式十、final 关键字十一、继承与组合 …

RK DWC3 gadget模块 分析

1. dw3 core代码分析 文件&#xff1a;[drivers/usb/dwc3/core.c] dwc3_probe 函数主要申请dwc3_vendor 参数内存&#xff08;dwc3_vendor的dwc成员即是 struct dwc3结构体参数&#xff09;&#xff0c;对dwc3 通过设备树 以及寄存器信息对 dwc3的成员进行初始化&#xff0c;…