06 Qt自绘组件:Switch动画开关组件

系列文章目录

01 Qt自定义风格控件的基本原则-CSDN博客

02 从QLabel聊起:自定义控件扩展-图片控件-CSDN博客

03 从QLabel聊起:自定义控件扩展-文本控件-CSDN博客

04 自定义Button组件:令人抓狂的QToolButton文本图标居中问题-CSDN博客

05 扩展组件:自定义CheckBox组件-CSDN博客


目录

系列文章目录

前言

一、示意效果

二、实现思路

1.概述

2.功能接口举例

3.部分渲染代码

1.动画触发时机

2.响应动画的数值变化以及状态变化

3.根据动画中间差值,渲染背景以及Handle

[3.1 渲染Switch背景色](#3.1 渲染Switch背景色)

[3.2 渲染Swith滑块](#3.2 渲染Swith滑块)

总结


前言

开关控件(Switch Control)不在Qt基本组件库里面,但是在我们的日常业务开发中极其常见。

开关控件通常用于在用户界面中表示两种状态(打开和关闭、开和关等),用户可以通过点击或拖动来切换状态。然而, 如果单纯的根据两种状态进行Icon的切换又略显单调些,所以本篇想向大家分享的是具有开关动画效果的Switch按钮组件!

既聊代码也说思路,我们开始今天的动画Swich动画开关组件的分享!


一、示意效果

二、实现思路

1.概述

1.为了沿用Qt 按钮组件的基本功能接口,所以我们继承的基类应该选择QAbstractButton而不是QWidget

2.从Swich组件的元素来看,我们可以拆解为三部分逻辑:

  • 圆角矩形背景
  • 圆形滑块
  • 滑块左右移动的动画

综上所述,我们需要用到的模块包括:

  • QPainterPath类:Qt 中用于描述和绘制复杂图形路径的类
  • QVariantAnimation:Qt 中用于执行属性动画的类,它可以用于对任意类型的属性进行动画效果的处理

2.功能接口举例

cpp 复制代码
class QUIEXTPLUGIN_EXPORT QUiSwitchButton : public QAbstractButton
{
    Q_OBJECT
    enum AnimationType
    {
        None= 0,      //静态状态下
        OnAnimation ,//打开动画从左向右滑动
        OffAnimation,    //关闭动画从右向左滑动
    };
public:
    QUiSwitchButton(QWidget *parent);
    ~QUiSwitchButton();
    //设置开状态下文本色
    void setSwitchOnTextColor(const QColor& clr);
    //设置关状态下文本色
    void setSwitchOffTextColor(const QColor& clr);
    //设置开状态下背景色
    void setSwitchOnColor(const QColor& clr);
    //设置关状态下背景色
    void setSwitchOffColor(const QColor& clr);
    //设置diasbale颜色
    void setSwitchDisableColor(const QColor& clr);
    //设置滑块背景色
    void setHandleColor(const QColor& clr);
protected:
    void mouseReleaseEvent(QMouseEvent *pEvt) override;
    void paintEvent(QPaintEvent *e) override;
    void drawBackground(QStylePainter*);
    void drawHandler(QStylePainter*);
    //
    void startAnimation();
    double getCurAnimaValue()const;
    QColor styledBackgroundColor()const;
protected slots:
    void handleAnimValueChanged(QVariant val);
    void handleAnimStateChanged(QVariantAnimation::State);
private:
    QPointer<QVariantAnimation> m_pAnima;
    QColor m_clrOnText;
    QColor m_clrOffText;
    QColor m_clrOn;
    QColor m_clrOff;
    QColor m_clrDisable;
    QColor m_clrHandler;
    int m_iHandlerMargin;
    double m_dCurFrame;
    AnimationType m_eCurAniType;
}

3.部分渲染代码

1.动画触发时机

cpp 复制代码
void QUiSwitchButton::mouseReleaseEvent(QMouseEvent *pEvt)
{
    startAnimation();
    QAbstractButton::mouseReleaseEvent(pEvt);
}

2.响应动画的数值变化以及状态变化

cpp 复制代码
void QUiSwitchButton::handleAnimStateChanged(QVariantAnimation::State curState)
{
    if (QVariantAnimation::Stopped == curState)
    {
        m_eCurAniType = None;
    }
    update();
}
cpp 复制代码
void QUiSwitchButton::handleAnimValueChanged(QVariant val)
{
    m_dCurFrame = val.toDouble();
    update();
}

3.根据动画中间差值,渲染背景以及Handle

cpp 复制代码
void QUiSwitchButton::paintEvent(QPaintEvent *pEvt)
{
    Q_UNUSED(pEvt);
    QStylePainter paint(this);
    paint.setRenderHints(QPainter::Antialiasing);
    drawBackground(&paint);
    drawHandler(&paint);
    drawText(&paint);
}

PS:这里要说的是,渲染顺序是有规则的,要根据元素的层级以及依赖顺序来决定

3.1 渲染Switch背景色

这里要注重点的是QPainterPath的使用以及其渲染规则的不同效果!

cpp 复制代码
void QUiSwitchButton::drawBackground(QStylePainter* paint)
{
    QRect rcFrame = contentsRect();
    QRect rcLeft = rcFrame;//左边圆弧
    QRect rcMiddle = rcFrame;//中间矩形
    QRect rcRight = rcFrame;//右边圆弧

    QPainterPath path;
    path.setFillRule(Qt::WindingFill);//设置填充规则
    //左
    rcLeft.setWidth(rcLeft.height());
    path.addEllipse(rcLeft);
    //中
    rcMiddle.adjust(rcLeft.width() / 2, 0, -rcLeft.width() / 2, 0);
    path.addRect(rcMiddle);
    //右
    rcRight.adjust(rcMiddle.width(), 0, 0, 0);
    path.addEllipse(rcRight);
    paint->fillPath(path, styledBackgroundColor());
}
3.2 渲染Swith滑块

这里的重点则是实时计算滑块的中心位置并计算

cpp 复制代码
void QUiSwitchButton::drawHandler(QStylePainter* paint)
{
    //以滑块中心为分界点
    QRect rcFrame = contentsRect();
    QRect rcHandler;
    int iAnimSpan = rcFrame.width() - rcFrame.height();
    QPoint ptCenter(rcFrame.width() - rcFrame.height() / 2 - iAnimSpan * (1.0 - getCurAnimaValue()), rcFrame.height() / 2);
    rcHandler = QRect(ptCenter.x() - rcFrame.height() / 2, 0, rcFrame.height(), rcFrame.height());
    rcHandler = rcHandler.marginsRemoved(QMargins(m_iHandlerMargin, m_iHandlerMargin, m_iHandlerMargin, m_iHandlerMargin));
    QPainterPath path;
    path.addEllipse(rcHandler);
    paint->fillPath(path, m_clrHandler);
}

总结

以上就是今天要分享的:Qt如何自绘 Switch开关动画按钮的内容!

既聊思路,也说代码!我们下次继续分享自定义风格扩展组件!

PS:本专栏所有篇幅涉及的UI扩展组件类,后面会封装成插件动态库,感兴趣的同学可以留言哦!

相关推荐
MarvinP15 分钟前
python基础:位置互换
开发语言·python·算法
Gauss松鼠会17 分钟前
GaussDB回调机制深度实践:从事件驱动到系统集成
开发语言·javascript·数据库·sql·gaussdb
独隅17 分钟前
Lua 函数使用的完整指南
开发语言·junit·lua·lua5.4
江沉晚呤时43 分钟前
深入解析策略模式在C#中的应用与实现
java·服务器·开发语言·前端·.netcore
居然是阿宋44 分钟前
Kotlin 中的 `reified` 关键字全解析:保留类型信息 + 优化高阶函数的双重魔法
android·开发语言·kotlin
安迪小宝1 小时前
python基础语法13-装饰器
开发语言·前端·python
小八四爱吃甜食1 小时前
【R语言绘图】圈图绘制代码
开发语言·r语言
残月只会敲键盘1 小时前
C++ Lambda表达式简明指南:新手快速上手
开发语言·c++
liwulin05062 小时前
【JAVA】JVM 堆内存“缓冲空间”的压缩机制及调整方法
java·开发语言·jvm
Simon—欧阳2 小时前
C#异步方法返回Task<T>的同步调用
开发语言·前端·javascript