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扩展组件类,后面会封装成插件动态库,感兴趣的同学可以留言哦!

相关推荐
Aric_Jones2 小时前
lua入门语法,包含安装,注释,变量,循环等
java·开发语言·git·elasticsearch·junit·lua
Akiiiira2 小时前
【日撸 Java 三百行】Day 12(顺序表(二))
java·开发语言
EndingCoder2 小时前
2025年JavaScript性能优化全攻略
开发语言·javascript·性能优化
码上淘金6 小时前
【Python】Python常用控制结构详解:条件判断、遍历与循环控制
开发语言·python
Brilliant Nemo6 小时前
四、SpringMVC实战:构建高效表述层框架
开发语言·python
格林威8 小时前
Baumer工业相机堡盟工业相机的工业视觉中为什么偏爱“黑白相机”
开发语言·c++·人工智能·数码相机·计算机视觉
橙子199110168 小时前
在 Kotlin 中什么是委托属性,简要说说其使用场景和原理
android·开发语言·kotlin
androidwork8 小时前
Kotlin Android LeakCanary内存泄漏检测实战
android·开发语言·kotlin
学地理的小胖砸9 小时前
【Python 基础语法】
开发语言·python
DanB2410 小时前
Java笔记4
java·开发语言·笔记