简介

  一般用来两种互斥状态的切换。

效果

下面放效果图

控件拆分

一、控件大体有两部分组成,一个是背景,一个是白色的滑块。原本背景是想用QWidget然后直接设置圆角的,然后发现效果很差。所以背景改成QPainter来绘制,拆分为2个180°的圆弧和一个矩形。

二、背景 = 左圆弧 + 矩形 + 右圆弧。有两种做法,一种就是字面上的做法,通过drawArc画两个圆弧,drawLine画上下两条线,然后填充。另外的简单粗暴做法就是直接左右两端画椭圆,中间画矩形,然后填充背景,类似下图做法。

三、滑块的动画个人做法是把整个按钮的宽度分成N等份,也就是width / N,得到的值就是每次滑块移动的距离,这边我直接称为步进(step)。然后通过定时器定时重绘按钮,每次重绘时,滑块的位置都是上次距离+步进,这样就形成一个简单的动画了。如果不要动画直接定义一个start和end的位置直接重绘就行了。

四、按钮的圆弧宽度和矩形宽度的话,个人是取宽高的最小值作为圆弧的半径,然后矩形宽度为宽高最大值减去宽高的最小值。当然这有个毛病,宽高一样的时候,button就是个圆形了,所以设置宽高时候,宽和高最好有10px左右的差值。

五、为了美观,滑块和背景最好有2~3px左右的间距。

2022/11/16修改

  感谢网友 jeneralriter 的指正。原本的switchbutton单独采用一个定时器,在大量控件或性能吃紧的情况下,会造成卡顿。现在将switchbutton拆为两个模块:一个背景Widget,一个滑块Widget。动画统一采用Qt的Animation管理,暂时避免大量定时器情况。

实现

#ifndef SWITCHBUTTON_H
#define SWITCHBUTTON_H#include <QWidget>class Slider;class SwitchButton : protected QWidget
{Q_OBJECTpublic:explicit SwitchButton(QWidget *parent = nullptr);~SwitchButton();/*** @brief SetSize 设置按钮的尺寸* @param nWidth 按钮的新宽度* @param nHeight 按钮的新高度*/void SetSize(int nWidth, int nHeight);/*** @brief SetActiveColor 设置按钮激活时候的颜色* @param color 激活颜色*/void SetActiveColor(const QColor& color);/*** @brief SetInactiveColor 设置按钮未激活时候的颜色* @param color 未激活颜色*/void SetInactiveColor(const QColor& color);/*** @brief SetSliderColor 设置滑块颜色* @param color 滑块的颜色*/void SetSliderColor(const QColor& color);/*** @brief SetStatus 设置按钮状态* @param bActive true: 激活,false: 未激活*/void SetStatus(bool bActive);/*** @brief GetStatus 获取按钮当前状态* @return  true: 激活,false: 未激活*/bool GetStatus() const;protected:void paintEvent(QPaintEvent *event) override;void mousePressEvent(QMouseEvent *event) override;/*** @brief ToActive 按钮状态变为Active*/void ToActive();/*** @brief ToInactive 按钮状态变为Inactive*/void ToInactive();private:bool m_bActive; // 是否激活int m_nArcRadius; // 圆弧的半径int m_nRectWidth; // 矩形的宽度const short m_nMargin = 2;const int m_nDuration = 100; // 动画时间,单位毫秒bool m_bClicked; // 能否被点击。如果动画还没结束,无法进行点击/状态切换QColor m_colorActive; // 激活时的颜色QColor m_colorInactive;Slider* m_pSlider;signals:/*** @brief Clicked 按钮被点击后发出的信号* @param status 当前按钮状态。true为active,false为inactive*/void Clicked(bool status);
};class Slider : public QWidget
{Q_OBJECT
public:explicit Slider(QWidget* parent = nullptr);~Slider();/*** @brief SetSliderColor 设置滑块颜色* @param color*/void SetSliderColor(const QColor& color);protected:void paintEvent(QPaintEvent* e) override;private:QColor m_sliderColor;
};#endif
#include "SwitchButton.h"
#include <QPainter>
#include <QPainterPath>
#include <QPropertyAnimation>SwitchButton::SwitchButton(QWidget *parent) :QWidget(parent)
{resize(60, 30); // 默认60,30宽高m_bClicked = true;m_pSlider = new Slider(this);m_pSlider->resize(height() - m_nMargin * 2, height() - m_nMargin * 2);m_pSlider->move(m_nMargin, m_nMargin);m_bActive = false; // 默认未激活m_nArcRadius = std::min(width(), height()); // 默认半径m_nRectWidth = width() - m_nArcRadius;m_colorActive = Qt::green;m_colorInactive = Qt::red;setCursor(QCursor(Qt::PointingHandCursor));
}SwitchButton::~SwitchButton()
{}void SwitchButton::SetSize(int nWidth, int nHeight)
{resize(nWidth, nHeight);m_pSlider->resize(height() - m_nMargin * 2, height() - m_nMargin * 2);m_pSlider->move(m_nMargin, m_nMargin);m_nArcRadius = std::min(width(), height());m_nRectWidth = width() - m_nArcRadius;
}void SwitchButton::SetActiveColor(const QColor& color)
{m_colorActive = color;
}void SwitchButton::SetInactiveColor(const QColor& color)
{m_colorInactive = color;
}void SwitchButton::SetSliderColor(const QColor& color)
{m_pSlider->SetSliderColor(color);
}void SwitchButton::SetStatus(bool bActive)
{if(m_bActive == bActive || !m_bClicked){return;}m_bClicked = false;m_bActive = bActive;if(m_bActive){ToActive();}else{ToInactive();}emit Clicked(m_bActive);
}bool SwitchButton::GetStatus() const
{return m_bActive;
}void SwitchButton::paintEvent(QPaintEvent *)
{QPainter p;p.begin(this);p.setRenderHint(QPainter::Antialiasing, true);p.setPen(Qt::NoPen);if(m_bActive) p.setBrush(QBrush(m_colorActive));else p.setBrush(QBrush(m_colorInactive));QPainterPath leftPath;leftPath.addEllipse(0, 0, m_nArcRadius, m_nArcRadius);QPainterPath middlePath;middlePath.addRect(m_nArcRadius / 2, 0, m_nRectWidth, m_nArcRadius);QPainterPath rightPath;rightPath.addEllipse(m_nRectWidth, 0, m_nArcRadius, m_nArcRadius);QPainterPath path = leftPath + middlePath + rightPath;p.drawPath(path);p.end();
}void SwitchButton::mousePressEvent(QMouseEvent *event)
{SetStatus(!m_bActive);QWidget::mousePressEvent(event);
}void SwitchButton::ToActive()
{QPropertyAnimation* pAnimation = new QPropertyAnimation(m_pSlider, "geometry");pAnimation->setDuration(m_nDuration);pAnimation->setStartValue(m_pSlider->rect());pAnimation->setEndValue(QRect(width() - m_pSlider->width() - m_nMargin,m_nMargin,m_pSlider->width(),m_pSlider->height()));connect(pAnimation, &QPropertyAnimation::finished, this, [&]{if(!m_bClicked){m_bClicked = true; // 结束后还原标识位}});connect(pAnimation, &QPropertyAnimation::valueChanged, this, [&](const QVariant &value){Q_UNUSED(value)update();});pAnimation->start(QAbstractAnimation::DeleteWhenStopped);
}void SwitchButton::ToInactive()
{QPropertyAnimation* pAnimation = new QPropertyAnimation(m_pSlider, "geometry");pAnimation->setDuration(m_nDuration);pAnimation->setStartValue(QRect(m_pSlider->x(),m_pSlider->y(),m_pSlider->width(),m_pSlider->height()));pAnimation->setEndValue(QRect(m_nMargin,m_nMargin,m_pSlider->width(),m_pSlider->height()));connect(pAnimation, &QPropertyAnimation::finished, this, [&]{if(!m_bClicked){m_bClicked = true; // 结束后还原标识位}});connect(pAnimation, &QPropertyAnimation::valueChanged, this, [&](const QVariant &value){Q_UNUSED(value)update();});pAnimation->start(QAbstractAnimation::DeleteWhenStopped);
}///
/// Slider  滑块类  //
//Slider::Slider(QWidget *parent) : QWidget(parent)
{m_sliderColor = Qt::white;resize(60, 60);
}Slider::~Slider()
{}void Slider::SetSliderColor(const QColor &color)
{m_sliderColor = color;update();
}void Slider::paintEvent(QPaintEvent *e)
{QPainter p(this);p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);p.fillRect(rect(), Qt::transparent);p.setBrush(m_sliderColor);p.setPen(Qt::NoPen);p.drawRoundedRect(rect(), width() / 2, height() / 2);QWidget::paintEvent(e);
}

若有更好的方法,评论区欢迎讨论指正~

其它控件

更多控件查看Qt自定义控件合集

Qt自定义控件------SwitchButton相关推荐

  1. Qt自定义控件创建和使用

    Qt自定义控件创建和使用 Qt中很方便的是使用各种自定义控件来分模块实现各种子功能,用于实现代码的解耦: 之前在使用Qt 5.12创建自定义控件时,出现了各种问题,多次重装QtCreator和VS,屡 ...

  2. Qt自定义控件之仪表盘的完整实现

    概述 基于QT的仪表盘有很多种办法,比如使用QWT,ChartDirector 或H5混合的echart组件,或者基于QT的绘图功能绘制,或者基于美工提供的图片的基础上增加动态效果.然而搞明白QT自定 ...

  3. Qt自定义控件(IP输入框,windows下)

    1.建立自定义控件项目 组代表后来能从哪里找到 剩下的点"下一步"就行了 2.编辑代码 在生成项目的cpp中添加自己的内容(没有.ui界面了,设计tab是灰色的) 放一下我的代码 ...

  4. linux qt 自定义控件,编写Qt Designer自定义控件(一)——如何创建并使用Qt自定义控件...

    要想在Qt Designer中使用自定义控件,必须要使Qt Designer能够知道我们的自定义控件的存在.有两种方法可以把新自定义控件的信息通知给Qt Designer:"升级(promo ...

  5. 【Qt开发笔记】Qt自定义控件开发与使用,自定义控件实现容器与控件内布局

    1.开发环境 Qt版本:Qt 4.8.7 编译器:MinGw 系统:Windows 2.创建Qt4自定义控件 创建一个Qt自定义控件工程. 工程名为Custom. 控件类取名Custom. 然后完成创 ...

  6. Qt自定义控件之圆形按钮、圆形头像

    Qt自定义控件之圆形按钮.圆形头像 前言 代码实现 实验效果 前言 现在很多软件的头像或者按钮都是圆形了,看起来比较舒服.比如QQ登录头像,酷狗客户端的一些按钮都是圆形.Qt实现圆形头像,大致有几种思 ...

  7. Qt 自定义控件提升,头文件找不到的问题

    Qt 自定义控件提升,头文件找不到的问题 在附加包含目录添加: ./

  8. QT自定义控件(生成和使用)

    为什么80%的码农都做不了架构师?>>>    首先,打开Qt Creator,这不是废话莫, → 新建项目 (快捷键 [ Ctrl + N ])→ 其他项目 → Qt4 设计师自定 ...

  9. 编写Qt Designer自定义控件(一)——如何创建并使用Qt自定义控件

    在使用Qt Designer设计窗体界面时,我们可以使用Widget Box里的窗体控件非常方便的绘制界面,比如拖进去一个按钮,一个文本编辑器等.虽然Qt Designer里的控件可以满足我们大部分的 ...

最新文章

  1. 使用LocalDate计算给定2个日期的几年几月几日
  2. C++中构造函数调用构造函数
  3. Java从零开始学六(运算符)
  4. 情人节,你们的CEO都在干嘛?
  5. logback基础配置文件
  6. 随机模块random、os模块、sys模块、shutil模块
  7. 递归算法时间复杂度计算
  8. 如何使用CNN进行物体识别和分类_RCNN物体识别
  9. mcq 队列_MCQ | 基础知识 免费和开源软件| 套装3
  10. [C/C++] 按行读取文件
  11. Python中的公共操作(运算符,公共方法,容器类型转换)
  12. 11 Steps Attackers Took to Crack Target
  13. 图书管理系统(前台(vue))
  14. c语言闰月的计算方法,2017 清宫图闰月的计算方法
  15. Protocol buffer配置-生成jar包和java文件
  16. 热备份冗余技术HSRP
  17. 华为路由器:ospf协议入门介绍
  18. linux下终端分屏使用
  19. STM32CubeMX安装问题【尤其是Java环境没安装好的情况】
  20. 计算机桌面输入法怎么恢复,电脑输入法图标不见了怎么办 电脑输入法图标消失找回【图文】...

热门文章

  1. 一个程序员的日常软件清单
  2. 全国高校地理信息排名
  3. JavaScript去除文本框中重复内容 js去重复
  4. 【C语言】将一个浮点数四舍五入保留两位小数
  5. 【观察】软件行业创新进入“新周期”,如何在变局中开新局?
  6. adb广告拦截 android,IT之家学院:使用adb揪出安卓后台弹窗广告APP原形
  7. 波音787航空电子系统座舱EFIS仿真软件研发
  8. 酒店管理系统(Java实现)
  9. PPT技术干货1(下)——数据图表分析、逻辑梳理、高效办公
  10. Java实现登录注册