1、功能介绍
在项目UI中使用较多的打开/关闭的开关按钮,一般都是找图片去做效果,比如说如下的图像来表征打开或关闭。
如果想要控件有打开/关闭的动画效果或比较好的视觉效果,这里就可以使用自定义控件,使用Painter来绘制控件。软件最终的效果如上图三:
2、主要的实现绘制代码
绘制背景区域
void SwitchButton::drawBackGround(QPainter *painter)
{
painter->save();
painter->setPen(Qt::NoPen);
QColor bgColor = m_checked ? m_bgColorOn : m_bgColorOff;
if (isEnabled()) {
bgColor.setAlpha(140);
}
painter->setBrush(bgColor);
QRect rect(0, 0, width(), height());
int side = qMin(width(), height());
//左侧半圆
QPainterPath path1;
path1.addEllipse(rect.x(), rect.y(), side, side);
//右侧半圆
QPainterPath path2;
path2.addEllipse(rect.width() - side, rect.y(), side, side);
//中间的矩形
QPainterPath path3;
path3.addRect(rect.x() + side / 2, rect.y(), rect.width() - side, height());
QPainterPath path = path1 + path2 + path3;
painter->drawPath(path);
//绘制文本
//滑块半径
int sliderWidth = qMin(height(), width()) - m_space * 2 - 5;
if (m_checked){
QRect textRect(0, 0, width() - sliderWidth, height());
painter->setPen(QPen(m_textColor));
painter->drawText(textRect, Qt::AlignCenter, m_textOn);
} else {
QRect textRect(sliderWidth, 0, width() - sliderWidth, height());
painter->setPen(QPen(m_textColor));
painter->drawText(textRect, Qt::AlignCenter, m_textOff);
}
painter->restore();
}
绘制滑块
void SwitchButton::drawSlider(QPainter *painter)
{
painter->save();
painter->setPen(Qt::NoPen);
QColor color = m_checked ? m_sliderColorOn : m_sliderColorOff;
painter->setBrush(QBrush(color));
int sliderWidth = qMin(width(), height()) - m_space * 2;
QRect rect(m_space + m_startX, m_space, sliderWidth, sliderWidth);
painter->drawEllipse(rect);
painter->restore();
}
这里引入了滑块动画效果,设定一个定时器,根据滑块的距离设置一个动画的效果
m_timer = new QTimer(this);
m_timer->setInterval(30);
connect(m_timer, SIGNAL(timeout()), this, SLOT(UpdateValue()));
void SwitchButton::UpdateValue()
{
if (m_checked) {
if (m_startX < m_endX) {
m_startX += m_step;
} else {
m_startX = m_endX;
m_timer->stop();
}
} else {
if (m_startX > m_endX) {
m_startX -= m_step;
} else {
m_startX = m_endX;
m_timer->stop();
}
}
update();
}
3、功能实现源码
switchButton.h
#ifndef SWITCHBUTTON_H
#define SWITCHBUTTON_H
#include <QObject>
#include <QWidget>
#include <QTimer>
#include <QColor>
class SwitchButton : public QWidget
{
Q_OBJECT
public:
explicit SwitchButton(QWidget *parent = nullptr);
signals:
void statusChanged(bool checked);
public slots:
private slots:
void UpdateValue();
private:
void drawBackGround(QPainter *painter);
void drawSlider(QPainter *painter);
protected:
void paintEvent(QPaintEvent *event);
void mousePressEvent(QMouseEvent *event);
private:
//滑块距离边界距离
int m_space;
//圆角角度
int m_radius;
//是否选中
bool m_checked;
//是否显示文本
bool m_showText;
//是否显示圆
bool m_showCircle;
//是否使用动画
bool m_animation;
//打开时候背景色
QColor m_bgColorOn;
//关闭时候背景色
QColor m_bgColorOff;
//打开时候滑块颜色
QColor m_sliderColorOn;
//关闭时候滑块颜色
QColor m_sliderColorOff;
//文字颜色
QColor m_textColor;
//打开时候文字
QString m_textOn;
//关闭时候文字
QString m_textOff;
//动画定时器
QTimer *m_timer;
//动画步长
int m_step;
//滑块开始X轴坐标
int m_startX;
//滑块介绍X轴坐标
int m_endX;
public:
int space() const;
int radius() const;
bool checked() const;
bool showText() const;
bool showCircle() const;
bool animation() const;
QColor bgColorOn() const;
QColor bgColorOff() const;
QColor sliderColorOn() const;
QColor sliderColorOff() const;
QColor textColor() const;
QString textOn() const;
QString textOff() const;
int step() const;
int startX() const;
int endX() const;
public Q_SLOTS:
void setSpace(int space);
void setRadius(int radius);
void setChecked(bool checked);
void setShowText(bool show);
void setShowCircle(bool show);
void setAnimation(bool ok);
void setBgColorOn(const QColor &color);
void setBgColorOff(const QColor &color);
void setSliderColorOn(const QColor &color);
void setSliderColorOff(const QColor &color);
void setTextColor(const QColor &color);
void setTextOn(const QString &text);
void setTextOff(const QString &text);
// void setStep(int step);
// void setStartX(int startX);
// void setEndX(int endX);
};
#endif // SWITCHBUTTON_H
switchButton.cpp
#pragma execution_character_set("utf-8")
#include "SwitchButton.h"
#include <QPainter>
SwitchButton::SwitchButton(QWidget *parent) : QWidget(parent)
{
m_space = 2;
m_radius = 5;
m_checked = false;
m_showText = true;
m_showText = false;
m_animation = true;
m_bgColorOn = QColor(21, 156, 119);
m_bgColorOff = QColor(111, 122, 126);
m_sliderColorOn = QColor(255, 255, 255);
m_sliderColorOff = QColor(255, 255, 255);
m_textColor = QColor(255, 255, 255);
m_textOn = "开启";
m_textOff = "关闭";
m_step = 0;
m_startX = 0;
m_endX = 0;
m_timer = new QTimer(this);
m_timer->setInterval(30);
connect(m_timer, SIGNAL(timeout()), this, SLOT(UpdateValue()));
}
void SwitchButton::drawBackGround(QPainter *painter)
{
painter->save();
painter->setPen(Qt::NoPen);
QColor bgColor = m_checked ? m_bgColorOn : m_bgColorOff;
if (isEnabled()) {
bgColor.setAlpha(140);
}
painter->setBrush(bgColor);
QRect rect(0, 0, width(), height());
int side = qMin(width(), height());
//左侧半圆
QPainterPath path1;
path1.addEllipse(rect.x(), rect.y(), side, side);
//右侧半圆
QPainterPath path2;
path2.addEllipse(rect.width() - side, rect.y(), side, side);
//中间的矩形
QPainterPath path3;
path3.addRect(rect.x() + side / 2, rect.y(), rect.width() - side, height());
QPainterPath path = path1 + path2 + path3;
painter->drawPath(path);
//绘制文本
//滑块半径
int sliderWidth = qMin(height(), width()) - m_space * 2 - 5;
if (m_checked){
QRect textRect(0, 0, width() - sliderWidth, height());
painter->setPen(QPen(m_textColor));
painter->drawText(textRect, Qt::AlignCenter, m_textOn);
} else {
QRect textRect(sliderWidth, 0, width() - sliderWidth, height());
painter->setPen(QPen(m_textColor));
painter->drawText(textRect, Qt::AlignCenter, m_textOff);
}
painter->restore();
}
void SwitchButton::drawSlider(QPainter *painter)
{
painter->save();
painter->setPen(Qt::NoPen);
QColor color = m_checked ? m_sliderColorOn : m_sliderColorOff;
painter->setBrush(QBrush(color));
int sliderWidth = qMin(width(), height()) - m_space * 2;
QRect rect(m_space + m_startX, m_space, sliderWidth, sliderWidth);
painter->drawEllipse(rect);
painter->restore();
}
void SwitchButton::paintEvent(QPaintEvent *ev)
{
//启用反锯齿
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
//绘制背景
drawBackGround(&painter);
//绘制滑块
drawSlider(&painter);
}
void SwitchButton::mousePressEvent(QMouseEvent *ev)
{
Q_UNUSED(ev)
m_checked = !m_checked;
emit statusChanged(m_checked);
//计算步长
m_step = width() / 10;
//计算滑块X轴终点坐标
if (m_checked) {
m_endX = width() - height();
} else {
m_endX = 0;
}
//判断是否使用动画
if (m_animation) {
m_timer->start();
} else{
m_startX = m_endX;
update();
}
}
void SwitchButton::UpdateValue()
{
if (m_checked) {
if (m_startX < m_endX) {
m_startX += m_step;
} else {
m_startX = m_endX;
m_timer->stop();
}
} else {
if (m_startX > m_endX) {
m_startX -= m_step;
} else {
m_startX = m_endX;
m_timer->stop();
}
}
update();
}
int SwitchButton::space() const
{
return m_space;
}
int SwitchButton::radius() const
{
return m_radius;
}
bool SwitchButton::checked() const
{
return m_checked;
}
bool SwitchButton::showText() const
{
return m_showText;
}
bool SwitchButton::showCircle() const
{
return m_showCircle;
}
bool SwitchButton::animation() const
{
return m_animation;
}
QColor SwitchButton::bgColorOn() const
{
return m_bgColorOn;
}
QColor SwitchButton::bgColorOff() const
{
return m_bgColorOff;
}
QColor SwitchButton::sliderColorOn() const
{
return m_sliderColorOn;
}
QColor SwitchButton::sliderColorOff() const
{
return m_sliderColorOff;
}
QColor SwitchButton::textColor() const
{
return m_textColor;
}
QString SwitchButton::textOn() const
{
return m_textOn;
}
QString SwitchButton::textOff() const
{
return m_textOff;
}
int SwitchButton::step() const
{
return m_step;
}
int SwitchButton::startX() const
{
return m_startX;
}
int SwitchButton::endX() const
{
return m_endX;
}
void SwitchButton::setSpace(int space)
{
if (m_space != space) {
m_space = space;
update();
}
}
void SwitchButton::setRadius(int radius)
{
if (m_radius != radius) {
m_radius = radius;
update();
}
}
void SwitchButton::setChecked(bool checked)
{
if (m_checked != checked) {
m_checked = checked;
update();
}
}
void SwitchButton::setShowText(bool show)
{
if (m_showText != show) {
m_showText = show;
update();
}
}
void SwitchButton::setShowCircle(bool show)
{
if (m_showCircle != show) {
m_showCircle = show;
update();
}
}
void SwitchButton::setAnimation(bool ok)
{
if (m_animation != ok) {
m_animation = ok;
update();
}
}
void SwitchButton::setBgColorOn(const QColor &color)
{
if (m_bgColorOn != color) {
m_bgColorOn = color;
update();
}
}
void SwitchButton::setBgColorOff(const QColor &color)
{
if (m_bgColorOff != color) {
m_bgColorOff = color;
update();
}
}
void SwitchButton::setSliderColorOn(const QColor &color)
{
if (m_sliderColorOn != color) {
m_sliderColorOn = color;
update();
}
}
void SwitchButton::setSliderColorOff(const QColor &color)
{
if (m_sliderColorOff != color) {
m_sliderColorOff = color;
update();
}
}
void SwitchButton::setTextColor(const QColor &color)
{
if (m_textColor != color) {
m_textColor = color;
update();
}
}
void SwitchButton::setTextOn(const QString &text)
{
if (m_textOn != text) {
m_textOn = text;
update();
}
}
void SwitchButton::setTextOff(const QString &text)
{
if (m_textOff != text) {
m_textOff = text;
update();
}
}
//void SwitchButton::setStep(int step)
//{
// if (m_step != step) {
// m_step = step;
// update();
// }
//}
//void SwitchButton::setStartX(int startX)
//{
//}
//void SwitchButton::setEndX(int endX)
//{
//}
4、效果与源码
控件实现的动态效果如下
本小例程的代码放到我的开源gitte项目里,欢迎一起学习,也希望能收获你的小星星。
源码SwitchButton