简述
接触过IOS系统的童鞋们应该对开关按钮很熟悉,在设置里面经常遇到,切换时候的滑动效果比较帅气。
通常说的开关按钮,有两个状态:on、off。
下面,我们利用自定义控件来实现一个开关按钮。
原理
- 重写鼠标按下事件(mousePressEvent)、释放事件(mouseReleaseEvent),用于切换开关状态。
- 重写绘制事件(paintEvent),用于绘制开关效果。
- 使用QTimer,定时刷新,让开关切换时产生动画效果。
其余接口用于扩展,也可自己扩充。
源码
SwitchControl.h
#ifndef SWITCH_CONTROL
#define SWITCH_CONTROL
#include <QWidget>
#include <QTimer>
class SwitchControl : public QWidget
{
Q_OBJECT
public:
explicit SwitchControl(QWidget *parent = 0);
bool isToggled() const;
void setToggle(bool checked);
void setBackgroundColor(QColor color);
void setCheckedColor(QColor color);
void setDisbaledColor(QColor color);
protected:
// 绘制开关
void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE;
QSize sizeHint() const Q_DECL_OVERRIDE;
QSize minimumSizeHint() const Q_DECL_OVERRIDE;
signals:
void toggled(bool checked);
private slots:
// 状态切换时,用于产生滑动效果
void onTimeout();
private:
bool m_bChecked;
QColor m_background;
QColor m_checkedColor;
QColor m_disabledColor;
QColor m_thumbColor;
qreal m_radius;
qreal m_nX;
qreal m_nY;
qint16 m_nHeight;
qint16 m_nMargin;
QTimer m_timer;
};
#endif // SWITCH_CONTROL
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
SwitchControl.cpp
#include <QPainter>
#include <QMouseEvent>
#include "SwitchControl.h"
SwitchControl::SwitchControl(QWidget *parent)
: QWidget(parent),
m_nHeight(16),
m_bChecked(false),
m_radius(8.0),
m_nMargin(3),
m_checkedColor(0, 150, 136),
m_thumbColor(Qt::white),
m_disabledColor(190, 190, 190),
m_background(Qt::black)
{
setCursor(Qt::PointingHandCursor);
connect(&m_timer, SIGNAL(timeout()), this, SLOT(onTimeout()));
}
void SwitchControl::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
QPainter painter(this);
painter.setPen(Qt::NoPen);
painter.setRenderHint(QPainter::Antialiasing);
QPainterPath path;
QColor background;
QColor thumbColor;
qreal dOpacity;
if (isEnabled()) {
if (m_bChecked) {
background = m_checkedColor;
thumbColor = m_checkedColor;
dOpacity = 0.600;
} else {
background = m_background;
thumbColor = m_thumbColor;
dOpacity = 0.800;
}
} else {
background = m_background;
dOpacity = 0.260;
thumbColor = m_disabledColor;
}
painter.setBrush(background);
painter.setOpacity(dOpacity);
path.addRoundedRect(QRectF(m_nMargin, m_nMargin, width() - 2 * m_nMargin, height() - 2 * m_nMargin), m_radius, m_radius);
painter.drawPath(path.simplified());
painter.setBrush(thumbColor);
painter.setOpacity(1.0);
painter.drawEllipse(QRectF(m_nX - (m_nHeight / 2), m_nY - (m_nHeight / 2), height(), height()));
}
void SwitchControl::mousePressEvent(QMouseEvent *event)
{
if (isEnabled()) {
if (event->buttons() & Qt::LeftButton) {
event->accept();
} else {
event->ignore();
}
}
}
void SwitchControl::mouseReleaseEvent(QMouseEvent *event)
{
if (isEnabled()) {
if ((event->type() == QMouseEvent::MouseButtonRelease) && (event->button() == Qt::LeftButton)) {
event->accept();
m_bChecked = !m_bChecked;
emit toggled(m_bChecked);
m_timer.start(10);
} else {
event->ignore();
}
}
}
void SwitchControl::resizeEvent(QResizeEvent *event)
{
m_nX = m_nHeight / 2;
m_nY = m_nHeight / 2;
QWidget::resizeEvent(event);
}
QSize SwitchControl::sizeHint() const
{
return minimumSizeHint();
}
QSize SwitchControl::minimumSizeHint() const
{
return QSize(2 * (m_nHeight + m_nMargin), m_nHeight + 2 * m_nMargin);
}
void SwitchControl::onTimeout()
{
if (m_bChecked) {
m_nX += 1;
if (m_nX >= width() - m_nHeight)
m_timer.stop();
} else {
m_nX -= 1;
if (m_nX <= m_nHeight / 2)
m_timer.stop();
}
update();
}
bool SwitchControl::isToggled() const
{
return m_bChecked;
}
void SwitchControl::setToggle(bool checked)
{
m_bChecked = checked;
m_timer.start(10);
}
void SwitchControl::setBackgroundColor(QColor color)
{
m_background = color;
}
void SwitchControl::setCheckedColor(QColor color)
{
m_checkedColor = color;
}
void SwitchControl::setDisbaledColor(QColor color)
{
m_disabledColor = color;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
示例
下面,我们来实现一组开关按钮。
效果

源码
为了演示,可以设置开关的样式、以及状态等效果。
SwitchControl *pSwitchControl = new SwitchControl(this);
SwitchControl *pGreenSwitchControl = new SwitchControl(this);
SwitchControl *pDisabledSwitchControl = new SwitchControl(this);
pGreenSwitchControl->setToggle(true);
pGreenSwitchControl->setCheckedColor(QColor(0, 160, 230));
pDisabledSwitchControl->setDisabled(true);
pDisabledSwitchControl->setToggle(true);
connect(pSwitchControl, SIGNAL(toggled(bool)), this, SLOT(onToggled(bool)));
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
实现一个简单的槽函数,当开关按钮效果变化时,就会触发,打印当前的状态。
void MainWindow::onToggled(bool bChecked)
{
qDebug() << "State : " << bChecked;
}
更多参考
源博客地址:http://blog.csdn.net/liang19890820/article/details/52164289