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

相关推荐
用户805533698034 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner4 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz9 天前
QML Hello World 入门示例
qt
xcyxiner12 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner13 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner13 天前
DicomViewer (添加模型类)3
qt
xcyxiner14 天前
DicomViewer (目录调整) 2
qt
xcyxiner14 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00616 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术16 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript