文章目录

一、效果展示

QT自定义控件--滑动按钮_数据结构

二、绘制过程

2.1、控件分析

滑动按钮主要由背景框和滑块组成。当点击按钮的时候,滑块就会滑到另一边,相应的背景框和滑块的颜色都会发生切换,所以可以将任务细分为三个:绘制背景框、绘制滑块、实现点击滑动。

2.2、原理详解

滑动按键的功能是:点击按钮时,滑块会滑动到另一边;为了捕捉点击动作就必须写一个按钮点击事件​​mousePressEvent()​​。为了实现滑块平滑的移动,可以使用定时器逐次移动(例如每10ms移动1/50的移动距离)。产生点击之后,将按钮的状态翻转,再计算出滑块的目标位置,并开启定时器实现逐次移动,移动要根据滑块的初始位置和目标位置来判断:当开关关闭时发生点击,滑块要向右滑动,初始位置+=移动步长,直到初始位置等于目标位置;当开关开启时发生点击,滑块要向左滑动,初始位置-=移动步长,直到初始位置等于目标位置。然后每次定时器计时到达就触发重绘事件,因为绘制滑块时会参考初始位置,所以就实现了滑块平滑的移动。

2.3、绘制背景框

void SwitchButton::drawBg(QPainter *painter)
{
painter->save();

painter->setPen(Qt::NoPen);
if (!checked)
{
painter->setBrush(bgColorOff);
}
else
{
painter->setBrush(bgColorOn);
}
painter->drawRoundedRect(rect(), rectRadius, rectRadius);

painter->restore();
}

2.4、绘制滑块

void SwitchButton::drawSlider(QPainter *painter)
{
painter->save();

painter->setPen(Qt::NoPen);
if (!checked) {
painter->setBrush(sliderColorOff);
} else {
painter->setBrush(sliderColorOn);
}
int sliderWidth = width() / 2 - space * 2;
int sliderHeight = height() - space * 2;
QRect sliderRect(startX + space, space, sliderWidth , sliderHeight);
painter->drawRoundedRect(sliderRect, rectRadius, rectRadius);

painter->restore();
}

2.5、其余代码

SwitchButton::SwitchButton(QWidget *parent): QWidget(parent)
{
checked = false;

//开、闭时背景颜色
bgColorOff = QColor(225, 225, 225);
bgColorOn = QColor(250, 250, 250);

//开、闭时滑块颜色
sliderColorOff = QColor(100, 100, 100);
sliderColorOn = QColor(100, 184, 255);

space = 2; //背景间隔
rectRadius = 5;

step = width() / 50; //步长

//起始、目标位置
startX = 0;
endX = 0;

timer = new QTimer(this);
timer->setInterval(10);
connect(timer, SIGNAL(timeout()), this, SLOT(updateValue()));

setFont(QFont("Microsoft Yahei", 10));
}

void SwitchButton::mousePressEvent(QMouseEvent *)
{
checked = !checked;
emit checkedChanged(checked);

//每次移动的步长为宽度的 50分之一
step = width() / 50;

//状态切换改变后自动计算终点坐标
if (checked)
{
endX = width() - width() / 2;
}
else
{
endX = 0;
}

timer->start();
}


void SwitchButton::updateValue()
{
if (checked) {
if (startX < endX) {
startX = startX + step;
} else {
startX = endX;
timer->stop();
}
} else {
if (startX > endX) {
startX = startX - step;
} else {
startX = endX;
timer->stop();
}
}

update();
}

void SwitchButton::resizeEvent(QResizeEvent *)
{
//每次移动的步长为宽度的 50分之一
step = width() / 50;

//尺寸大小改变后自动设置起点坐标为终点
if (checked)
{
startX = width() - width() / 2;
}
else
{
startX = 0;
}

update();
}

void SwitchButton::paintEvent(QPaintEvent *)
{
//绘制准备工作,启用反锯齿
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);

//绘制背景
drawBg(&painter);
//绘制滑块
drawSlider(&painter);
}