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

相关推荐
人邮异步社区20 分钟前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大1 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai1 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
এ慕ོ冬℘゜1 小时前
前端基础:什么是时间戳?JS获取时间戳三种方法与实战用途
开发语言·前端·javascript
执明wa1 小时前
LayoutInflater详解: XML是如何变成View的?
android·xml·开发语言·android studio
一次旅行1 小时前
Python+大模型端到端自动化日报系统
开发语言·python·自动化
噢,我明白了3 小时前
java中Excel的导入和导出(EasyExcel)
java·开发语言·excel
mabing9933 小时前
Qt 生成条纹图
开发语言·qt
蓝悦无人机3 小时前
C++基础 — 函数总结
开发语言·c++
糖果店的幽灵3 小时前
langgraph的 MessagesState 解读
java·开发语言·人工智能·windows·langgraph