简述
接触过IOS系统的童鞋们应该对开关按钮很熟悉,在设置里面经常遇到,切换时候的滑动效果比较帅气。
通常说的开关按钮,有两个状态:on、off。
下面,我们利用自定义控件来实现一个开关按钮。
原理
- 重写鼠标按下事件(mousePressEvent)、释放事件(mouseReleaseEvent),用于切换开关状态。
- 重写绘制事件(paintEvent),用于绘制开关效果。
- 使用QTimer,定时刷新,让开关切换时产生动画效果。
其余接口用于扩展,也可自己扩充。
源码
SwitchControl.h
#ifndef SWITCH_CONTROL#define SWITCH_CONTROL#include <QWidget>#include <QTimer>class SwitchControl : public QWidget{ Q_OBJECTpublic: 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)));
实现一个简单的槽函数,当开关按钮效果变化时,就会触发,打印当前的状态。
void MainWindow::onToggled(bool bChecked){ qDebug() << "State : " << bChecked;}
更多参考
- Toggle Switch in Qt
- Qt之QCheckBox
- Qt之QRadioButton
源博客地址:http://blog.csdn.net/liang19890820/article/details/52164289