SwitchButton效果
今天和大家分享一个基于Qt实现的自定义开关按钮-SwitchButton,可以在程序中用SwitchButton代替QRadioButton或QCheckBox进行一些使能的控制,不仅能实现同样的功能,而且外观和动态效果很现代化,使程序更加美观。平时我们用的很多软件里面也都有SwitchButton的使用,比如手机设置中的流量开关、飞行模式开关等,如下图所示:
然后再看一下我自定义的SwitchButton实现相同的效果和外观:
变个颜色再看看:
还可以加上提示文字:
额,看来看去还是第一种好看啊,其他的感觉不耐看,而且有种花里胡哨的感觉,所以人家手机厂商的设计师这样设计也不是没道理的嘛。
实现代码
SwitchButton.h
#ifndef SWITCHBUTTON_H#define SWITCHBUTTON_H#include #include #include class SwitchButton : public QWidget{ Q_OBJECTpublic: SwitchButton(QWidget *parent); ~SwitchButton();private: bool bSwitch; //开关状态:开true,关false QColor bgColorOn; //开状态时的背景颜色 QColor bgColorOff; //关状态时的背景颜色 QColor sliderColor; QColor sliderColorOn; //开状态时滑块的背景颜色 QColor sliderColorOff; //关状态时滑块的背景颜色 QColor textColorOn; //开状态时文字颜色 QColor textColorOff; //关状态时文字颜色 QString strText; //文字内容 QPoint startPoint; //滑块移动的起始点 QPoint endPoint; //滑块移动的终点 QPoint centerPoint; //滑块移动的中间某点 int mouseX; bool bPress; //左键是否按下private: void paintEvent(QPaintEvent *e); void resizeEvent(QResizeEvent *e); void mousePressEvent(QMouseEvent *e); void mouseMoveEvent(QMouseEvent *e); void mouseReleaseEvent(QMouseEvent *e); void drawBg(QPainter& painter); //绘制背景 void drawSlidBlock(QPainter& painter); //绘制滑块 void drawText(QPainter& painter); //绘制文字signals: void stateChange(bool state);};#endif // SWITCHBUTTON_H
SwitchButton.cpp
#include "SwitchButton.h"#include SwitchButton::SwitchButton(QWidget *parent) : QWidget(parent){ bSwitch = false; bgColorOff = QColor(192,192,192); bgColorOn = QColor(50,205,50); sliderColorOff = QColor(255, 255, 255); sliderColorOn = QColor(255, 255, 255);// sliderColorOff = QColor(100, 100, 100);// sliderColorOn = QColor(100, 184, 255); sliderColor = sliderColorOff; textColorOn = QColor(255,255,255); textColorOff = QColor(0,0,0); mouseX = 0; bPress = false;}SwitchButton::~SwitchButton(){}void SwitchButton::mousePressEvent(QMouseEvent *e){ if (e->button() == Qt::LeftButton) { if ((e->pos().x() - centerPoint.x())*(e->pos().y() - centerPoint.y()) <= ((rect().height()/2) * (rect().height()/2))) { bPress = true; mouseX = e->pos().x(); sliderColor = QColor(160,30,30); update(); } }}void SwitchButton::mouseMoveEvent(QMouseEvent *e){ if (bPress) { if ((e->pos().x() >= startPoint.x()) && (e->pos().x() <= endPoint.x())) { int tempX = e->pos().x(); centerPoint.setX(tempX - mouseX + centerPoint.x()); mouseX = centerPoint.x(); update(); } }}void SwitchButton::mouseReleaseEvent(QMouseEvent *e){ bPress = false; sliderColor = QColor(245,245,245); if (centerPoint.x() >= rect().width()/2) { centerPoint.setX(endPoint.x()); sliderColor = sliderColorOn; if(!bSwitch) emit stateChange(true); bSwitch = true; } else if (centerPoint.x() < rect().width()/2) { centerPoint.setX(startPoint.x()); sliderColor = sliderColorOff; if(bSwitch) emit stateChange(false); bSwitch = false; } update();}void SwitchButton::resizeEvent(QResizeEvent *e){ startPoint = QPoint(rect().height()/2,rect().height()/2); centerPoint = startPoint; endPoint = QPoint((rect().right() - rect().height()/2),rect().height()/2);}void SwitchButton::paintEvent(QPaintEvent *e){ QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); drawBg(painter); drawSlidBlock(painter); drawText(painter);}// 绘制背景void SwitchButton::drawBg(QPainter& painter){ painter.save(); painter.setPen(Qt::NoPen); if (bSwitch) { painter.setBrush(QBrush(bgColorOn)); } else { painter.setBrush(QBrush(bgColorOff)); } // 绘制按钮外边框 QPainterPath path; int startX = rect().height()/2; int startY = rect().top(); path.moveTo(startX,startY); path.arcTo(QRect(rect().left(),rect().top(),rect().height(),rect().height()),90,180); path.lineTo((rect().right() - startX),rect().height()); path.arcTo(QRect((rect().right() - rect().height()),rect().top(),rect().height(),rect().height()),270,180); path.lineTo(startX,startY); painter.drawPath(path); painter.restore();}// 绘制滑块void SwitchButton::drawSlidBlock(QPainter& painter){ painter.save(); painter.setPen(Qt::NoPen); painter.setBrush(QBrush(sliderColor)); painter.drawEllipse(centerPoint,rect().height()/2 - 2,rect().height()/2 - 2); painter.restore();}void SwitchButton::drawText(QPainter& painter){ painter.save(); QFont font("Microsoft YaHei", 12, 50, false); painter.setFont(font); int x,y; if (bSwitch) { painter.setPen(QPen(textColorOn)); x = rect().left(); y = rect().top(); strText = "";//QString("开"); } else { painter.setPen(QPen(textColorOff)); x = rect().right() - rect().height(); y = rect().top(); strText = "";//QString("关"); } painter.drawText(x,y,rect().height(),rect().height(),Qt::AlignCenter,strText); painter.restore();}
使用方法
#include "SwitchButton.h"#include SwitchButton::SwitchButton(QWidget *parent) : QWidget(parent){ bSwitch = false; bgColorOff = QColor(192,192,192); bgColorOn = QColor(50,205,50); sliderColorOff = QColor(255, 255, 255); sliderColorOn = QColor(255, 255, 255);// sliderColorOff = QColor(100, 100, 100);// sliderColorOn = QColor(100, 184, 255); sliderColor = sliderColorOff; textColorOn = QColor(255,255,255); textColorOff = QColor(0,0,0); mouseX = 0; bPress = false;}SwitchButton::~SwitchButton(){}void SwitchButton::mousePressEvent(QMouseEvent *e){ if (e->button() == Qt::LeftButton) { if ((e->pos().x() - centerPoint.x())*(e->pos().y() - centerPoint.y()) <= ((rect().height()/2) * (rect().height()/2))) { bPress = true; mouseX = e->pos().x(); sliderColor = QColor(160,30,30); update(); } }}void SwitchButton::mouseMoveEvent(QMouseEvent *e){ if (bPress) { if ((e->pos().x() >= startPoint.x()) && (e->pos().x() <= endPoint.x())) { int tempX = e->pos().x(); centerPoint.setX(tempX - mouseX + centerPoint.x()); mouseX = centerPoint.x(); update(); } }}void SwitchButton::mouseReleaseEvent(QMouseEvent *e){ bPress = false; sliderColor = QColor(245,245,245); if (centerPoint.x() >= rect().width()/2) { centerPoint.setX(endPoint.x()); sliderColor = sliderColorOn; if(!bSwitch) emit btnState(true); bSwitch = true; } else if (centerPoint.x() < rect().width()/2) { centerPoint.setX(startPoint.x()); sliderColor = sliderColorOff; if(bSwitch) emit btnState(false); bSwitch = false; } update();}void SwitchButton::resizeEvent(QResizeEvent *e){ startPoint = QPoint(rect().height()/2,rect().height()/2); centerPoint = startPoint; endPoint = QPoint((rect().right() - rect().height()/2),rect().height()/2);}void SwitchButton::paintEvent(QPaintEvent *e){ QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); drawBg(painter); drawSlidBlock(painter); drawText(painter);}// 绘制背景void SwitchButton::drawBg(QPainter& painter){ painter.save(); painter.setPen(Qt::NoPen); if (bSwitch) { painter.setBrush(QBrush(bgColorOn)); } else { painter.setBrush(QBrush(bgColorOff)); } // 绘制按钮外边框 QPainterPath path; int startX = rect().height()/2; int startY = rect().top(); path.moveTo(startX,startY); path.arcTo(QRect(rect().left(),rect().top(),rect().height(),rect().height()),90,180); path.lineTo((rect().right() - startX),rect().height()); path.arcTo(QRect((rect().right() - rect().height()),rect().top(),rect().height(),rect().height()),270,180); path.lineTo(startX,startY); painter.drawPath(path); painter.restore();}// 绘制滑块void SwitchButton::drawSlidBlock(QPainter& painter){ painter.save(); painter.setPen(Qt::NoPen); painter.setBrush(QBrush(sliderColor)); painter.drawEllipse(centerPoint,rect().height()/2 - 2,rect().height()/2 - 2); painter.restore();}void SwitchButton::drawText(QPainter& painter){ painter.save(); QFont font("Microsoft YaHei", 12, 50, false); painter.setFont(font); int x,y; if (bSwitch) { painter.setPen(QPen(textColorOn)); x = rect().left(); y = rect().top(); strText = "";//QString("开"); } else { painter.setPen(QPen(textColorOff)); x = rect().right() - rect().height(); y = rect().top(); strText = "";//QString("关"); } painter.drawText(x,y,rect().height(),rect().height(),Qt::AlignCenter,strText); painter.restore();}
其他用法
我在SwitchButton.h中添加了一个stateChange(bool)的信号,在重载的鼠标释放事件mouseReleaseEvent(QMouseEvent*)中emit这个信号,所以我们还可以通过将一个槽绑定到这个信号上的方法来监测状态改变,从而进行一些额外的操作,比如状态改变以后的提醒或者状态改变二次确认,防止误操作等,使用方法如下:
//连接信号和槽connect(btn1, SIGNAL(stateChange(bool)), this, SLOT(OnStateChange(bool)));
void Widget::OnStateChange(bool bState){ if (bState) qDebug() << "蜂窝数据已打开"; else qDebug() << "蜂窝数据已关闭";}
运行效果:
总结
代码只是个示例,当然可以直接使用,但是我写的比较急,就没有注意封装,因为现在已经0点以后了,明天还要上班(-_-||)。大家如果要使用的话可以把颜色设置,文字设置等功能都封装成方法,在外部直接调用,我这里都是在构造函数中直接写死的。封装起来,也很简单,代码量也很少,大家不妨试一试。