• 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.2 渲染Swith滑块 

    总结


    前言

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

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

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


    一、示意效果

    二、实现思路

    1.概述

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

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

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

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

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

    2.功能接口举例

    1. class QUIEXTPLUGIN_EXPORT QUiSwitchButton : public QAbstractButton
    2. {
    3. Q_OBJECT
    4. enum AnimationType
    5. {
    6. None= 0, //静态状态下
    7. OnAnimation ,//打开动画从左向右滑动
    8. OffAnimation, //关闭动画从右向左滑动
    9. };
    10. public:
    11. QUiSwitchButton(QWidget *parent);
    12. ~QUiSwitchButton();
    13. //设置开状态下文本色
    14. void setSwitchOnTextColor(const QColor& clr);
    15. //设置关状态下文本色
    16. void setSwitchOffTextColor(const QColor& clr);
    17. //设置开状态下背景色
    18. void setSwitchOnColor(const QColor& clr);
    19. //设置关状态下背景色
    20. void setSwitchOffColor(const QColor& clr);
    21. //设置diasbale颜色
    22. void setSwitchDisableColor(const QColor& clr);
    23. //设置滑块背景色
    24. void setHandleColor(const QColor& clr);
    25. protected:
    26. void mouseReleaseEvent(QMouseEvent *pEvt) override;
    27. void paintEvent(QPaintEvent *e) override;
    28. void drawBackground(QStylePainter*);
    29. void drawHandler(QStylePainter*);
    30. //
    31. void startAnimation();
    32. double getCurAnimaValue()const;
    33. QColor styledBackgroundColor()const;
    34. protected slots:
    35. void handleAnimValueChanged(QVariant val);
    36. void handleAnimStateChanged(QVariantAnimation::State);
    37. private:
    38. QPointer m_pAnima;
    39. QColor m_clrOnText;
    40. QColor m_clrOffText;
    41. QColor m_clrOn;
    42. QColor m_clrOff;
    43. QColor m_clrDisable;
    44. QColor m_clrHandler;
    45. int m_iHandlerMargin;
    46. double m_dCurFrame;
    47. AnimationType m_eCurAniType;
    48. }

    3.部分渲染代码

    1.动画触发时机

    1. void QUiSwitchButton::mouseReleaseEvent(QMouseEvent *pEvt)
    2. {
    3. startAnimation();
    4. QAbstractButton::mouseReleaseEvent(pEvt);
    5. }

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

    1. void QUiSwitchButton::handleAnimStateChanged(QVariantAnimation::State curState)
    2. {
    3. if (QVariantAnimation::Stopped == curState)
    4. {
    5. m_eCurAniType = None;
    6. }
    7. update();
    8. }
    1. void QUiSwitchButton::handleAnimValueChanged(QVariant val)
    2. {
    3. m_dCurFrame = val.toDouble();
    4. update();
    5. }

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

    1. void QUiSwitchButton::paintEvent(QPaintEvent *pEvt)
    2. {
    3. Q_UNUSED(pEvt);
    4. QStylePainter paint(this);
    5. paint.setRenderHints(QPainter::Antialiasing);
    6. drawBackground(&paint);
    7. drawHandler(&paint);
    8. drawText(&paint);
    9. }

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

    3.1 渲染Switch背景色 

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

    1. void QUiSwitchButton::drawBackground(QStylePainter* paint)
    2. {
    3. QRect rcFrame = contentsRect();
    4. QRect rcLeft = rcFrame;//左边圆弧
    5. QRect rcMiddle = rcFrame;//中间矩形
    6. QRect rcRight = rcFrame;//右边圆弧
    7. QPainterPath path;
    8. path.setFillRule(Qt::WindingFill);//设置填充规则
    9. //左
    10. rcLeft.setWidth(rcLeft.height());
    11. path.addEllipse(rcLeft);
    12. //中
    13. rcMiddle.adjust(rcLeft.width() / 2, 0, -rcLeft.width() / 2, 0);
    14. path.addRect(rcMiddle);
    15. //右
    16. rcRight.adjust(rcMiddle.width(), 0, 0, 0);
    17. path.addEllipse(rcRight);
    18. paint->fillPath(path, styledBackgroundColor());
    19. }
    3.2 渲染Swith滑块 

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

    1. void QUiSwitchButton::drawHandler(QStylePainter* paint)
    2. {
    3. //以滑块中心为分界点
    4. QRect rcFrame = contentsRect();
    5. QRect rcHandler;
    6. int iAnimSpan = rcFrame.width() - rcFrame.height();
    7. QPoint ptCenter(rcFrame.width() - rcFrame.height() / 2 - iAnimSpan * (1.0 - getCurAnimaValue()), rcFrame.height() / 2);
    8. rcHandler = QRect(ptCenter.x() - rcFrame.height() / 2, 0, rcFrame.height(), rcFrame.height());
    9. rcHandler = rcHandler.marginsRemoved(QMargins(m_iHandlerMargin, m_iHandlerMargin, m_iHandlerMargin, m_iHandlerMargin));
    10. QPainterPath path;
    11. path.addEllipse(rcHandler);
    12. paint->fillPath(path, m_clrHandler);
    13. }

    总结

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

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

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

  • 相关阅读:
    改造xxl-job适配nacos注册中心
    降噪耳机哪款比较舒适?比较舒适的降噪耳机盘点
    Ollama:本地部署大模型 + LobeChat:聊天界面 = 自己的ChatGPT
    详解Java堆的应用场景,思路分析,代码实现
    【优化算法】基于matlab反向策略的麻雀搜索算法【含Matlab源码 1918期】
    利用postman完成JSON串的发送功能(springboot)
    ZZNUOJ_用C语言编写程序实现1342:支配值数目(附完整源码)
    测试用例的8大设计原则
    Android 12 WiFi Scan 流程 [3]
    Target EDI 对接详解 – Partner Online EDI 注册
  • 原文地址:https://blog.csdn.net/HYNzhl/article/details/136267684