*最终效果:
*
一共三个文件: main.cpp , FancyCheckbox.h , FancyCheckbox.cpp
main.cpp
cpp
#include <QApplication>
#include "FancyCheckbox.h"
#include <QGridLayout>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget* w = new QWidget;
w->setWindowTitle("cool checkbox");
w->resize(600,400);
auto* layout = new QGridLayout;
layout->addWidget(new CheckboxSimple,0,0);
layout->addWidget(new CheckboxLollipop,0,1);
layout->addWidget(new CheckboxNike,0,2);
layout->addWidget(new CheckboxTransform,1,0);
layout->addWidget(new CheckboxBanner,1,1);
layout->addWidget(new CheckboxMark,1,2);
w->setLayout(layout);
w->show();
return a.exec();
}
FancyCheckbox.h
cpp
#ifndef CHECKBOXSIMPLE_H
#define CHECKBOXSIMPLE_H
#include <QPropertyAnimation>
#include <QWidget>
#include <QPaintEvent>
#include <QMouseEvent>
class CheckboxBase:public QWidget
{
Q_OBJECT
Q_PROPERTY(qreal angle READ angle WRITE setAngle)
public:
CheckboxBase(QWidget* parent=nullptr);
virtual ~CheckboxBase();
qreal angle()const;
void setAngle(qreal an);
protected:
void enterEvent(QEvent* e);
void leaveEvent(QEvent* e);
QPropertyAnimation mAnim;
qreal mAngle;
bool mChecked;
};
class CheckboxSimple : public CheckboxBase
{
Q_OBJECT
public:
explicit CheckboxSimple(QWidget *parent = nullptr);
protected:
void paintEvent(QPaintEvent* e);
void mouseReleaseEvent(QMouseEvent* e);
};
class CheckboxLollipop : public CheckboxBase
{
Q_OBJECT
public:
explicit CheckboxLollipop(QWidget *parent = nullptr);
protected:
void paintEvent(QPaintEvent* e);
void mouseReleaseEvent(QMouseEvent* e);
};
class CheckboxNike: public CheckboxBase{
Q_OBJECT
public:
explicit CheckboxNike(QWidget *parent = nullptr);
protected:
void paintEvent(QPaintEvent* e);
void mouseReleaseEvent(QMouseEvent* e);
};
class CheckboxTransform: public CheckboxBase{
Q_OBJECT
public:
explicit CheckboxTransform(QWidget *parent = nullptr);
protected:
void paintEvent(QPaintEvent* e);
void mouseReleaseEvent(QMouseEvent* e);
};
class CheckboxBanner: public CheckboxBase{
Q_OBJECT
public:
explicit CheckboxBanner(QWidget *parent = nullptr);
protected:
void paintEvent(QPaintEvent* e);
void mouseReleaseEvent(QMouseEvent* e);
};
class CheckboxMark: public CheckboxBase{
Q_OBJECT
public:
explicit CheckboxMark(QWidget *parent = nullptr);
protected:
void paintEvent(QPaintEvent* e);
void mouseReleaseEvent(QMouseEvent* e);
};
#endif // CHECKBOXSIMPLE_H
FancyCheckbox.cpp
cpp
#include "FancyCheckbox.h"
#include <QPainter>
#include <QPainterPath>
#include <QPalette>
#include <math.h>
CheckboxBase::CheckboxBase(QWidget* parent):
QWidget(parent),mAngle(0),mChecked(false)
{
mAnim.setPropertyName("angle");
mAnim.setTargetObject(this);
mAnim.setDuration(2000);
mAnim.setLoopCount(1);
mAnim.setEasingCurve(QEasingCurve::Linear);
setMouseTracking(true);
}
CheckboxBase::~CheckboxBase(){}
qreal CheckboxBase::angle()const{ return mAngle;}
void CheckboxBase::setAngle(qreal an){
mAngle = an;
update();
}
void CheckboxBase::enterEvent(QEvent* e){
setCursor(Qt::PointingHandCursor);
}
void CheckboxBase::leaveEvent(QEvent* e){
setCursor(Qt::ArrowCursor);
}
CheckboxSimple::CheckboxSimple(QWidget *parent) : CheckboxBase(parent)
{
setFixedSize(40,24);
mAnim.setDuration(100);
mAngle = 360;
}
void CheckboxSimple::paintEvent(QPaintEvent* e){
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
int w = width();
int h = height();
painter.setPen(Qt::NoPen);
if(mChecked){
painter.setBrush(QBrush(QColor("lightgreen")));
}
else{
painter.setBrush(QBrush(QColor("lightgray")));
}
painter.drawRoundedRect(rect(),h/2,h/2);
painter.setBrush(QBrush(QColor("white")));
const int gap = 3;
if(mChecked){
painter.translate((w-h)*mAngle/360+h/2,h/2);
}
else{
painter.translate(w-h/2-(w-h)*mAngle/360 , h/2);
}
painter.drawEllipse(QPoint(0,0),h/2-gap,h/2-gap);
}
void CheckboxSimple::mouseReleaseEvent(QMouseEvent* e){
if(mAnim.state() == QAbstractAnimation::Running) return;
mChecked = !mChecked;
mAnim.setStartValue(0);
mAnim.setEndValue(360);
mAnim.start();
}
CheckboxLollipop::CheckboxLollipop(QWidget *parent) : CheckboxBase(parent)
{
setFixedSize(80,72);
mAnim.setDuration(160);
mAngle = 360;
}
void CheckboxLollipop::paintEvent(QPaintEvent* e){
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
int w = width();
int h = height();
painter.setPen(Qt::NoPen);
if(mChecked){
painter.setBrush(QBrush(QColor("cornflowerblue")));
}
else{
painter.setBrush(QBrush(QColor("gray")));
}
const auto r = 0.16 * h;
const auto R = r + 0.25*w;
painter.translate(0.25*w,0.4*h);
if(mChecked){
if(mAngle <= 180){//move to rightside
painter.drawRoundedRect(QRectF(0,0,0.5*w,0.2*h),0.1*h,0.1*h);
painter.setBrush(QBrush(QColor("blueviolet")));
painter.translate((0.5*w - 2*r) * mAngle / 180 + r , 0.1*h);
painter.drawEllipse(QPointF(0,0),r,r);
}
else{//boom!
painter.translate(0.5*w - r,0.1*h);
QRadialGradient rad(QPointF(0,0),R,QPointF(0,0));
QColor base("blueviolet");
base.setAlphaF(0.3);
rad.setColorAt(0,base);
rad.setColorAt(1,"transparent");
QColor eraseColor("white");
QWidget * pa = dynamic_cast<QWidget*>( parent() );
if(pa){
eraseColor = pa->palette().color(QPalette::Window);
}
painter.setBrush(rad);
painter.drawEllipse(QPointF(0,0) , R , R);//画一个固定的渐变圈
painter.setBrush(QBrush(eraseColor));
auto out = r + (R -r) * ( mAngle - 180) / 180;
painter.drawEllipse(QPointF(0,0), out,out);//画一个逐渐变大的圈把渐变圈覆盖掉
painter.resetTransform();
painter.translate(0.25*w,0.4*h);
painter.setBrush(QBrush(QColor("cornflowerblue")));
painter.drawRoundedRect(QRectF(0,0,0.5*w,0.2*h),0.1*h,0.1*h);
painter.setBrush(QBrush(QColor("blueviolet")));
painter.translate((0.5*w - r) , 0.1*h);
painter.drawEllipse(QPointF(0,0),r,r);
}
}
else{
painter.drawRoundedRect(QRectF(0,0,0.5*w,0.2*h),0.1*h,0.1*h);
painter.setBrush(QBrush(QColor("white")));
painter.translate(0.5*w-r-((0.5*w-2*r) * mAngle/360),0.1*h);
painter.drawEllipse(QPointF(0,0),r,r);
}
}
void CheckboxLollipop::mouseReleaseEvent(QMouseEvent* e){
if(mAnim.state() == QAbstractAnimation::Running) return;
mChecked = !mChecked;
mAnim.setStartValue(0);
mAnim.setEndValue(360);
mAnim.start();
}
CheckboxNike::CheckboxNike(QWidget *parent){
setFixedSize(32,32);
mAngle = 360;
}
void CheckboxNike::paintEvent(QPaintEvent* e){
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(Qt::NoPen);
const int w = width();
const int h = height();
const int r = 8;
if(mChecked){
painter.setBrush(QBrush(QColor("lightblue")));
painter.drawRoundedRect(rect() , r,r);
QPainterPath cover;
cover.addRect(QRectF(0,0,w*mAngle/360,h));
painter.setClipPath(cover);
painter.setPen(Qt::white);
painter.setFont(QFont("Microsoft YaHei",12));
painter.drawText(rect() , Qt::AlignCenter , "✔");
}
else{
QColor baseBack("lightblue");
QColor baseFront("white");
baseBack.setAlphaF(1 - mAngle / 360);
baseFront.setAlphaF(1 - mAngle / 360);
painter.setBrush(baseBack);
painter.drawRoundedRect(rect() , r,r);
painter.setPen(baseFront);
painter.setFont(QFont("Microsoft YaHei",12));
painter.drawText(rect() , Qt::AlignCenter , "✔");
QPen pen(QBrush("lightblue"),4);
painter.setPen(pen);
painter.setBrush(Qt::NoBrush);
painter.drawRoundedRect(rect().adjusted(2,2,-2,-2) , r,r);
}
}
void CheckboxNike::mouseReleaseEvent(QMouseEvent* e){
if(mAnim.state() == QAbstractAnimation::Running) return;
mChecked = !mChecked;
mAnim.setStartValue(0);
mAnim.setEndValue(360);
if(mChecked){
mAnim.setDuration(200);
}
else{
mAnim.setDuration(100);
}
mAnim.start();
}
CheckboxTransform::CheckboxTransform(QWidget *parent){
setFixedSize(40,40);
mAngle = 360;
mAnim.setDuration(200);
}
void CheckboxTransform::paintEvent(QPaintEvent* e){
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
QPen pen("black");
pen.setWidth(2);
painter.setPen(pen);
painter.setBrush(Qt::NoBrush);
const double w = width();
const double h = height();
painter.translate(0.25*w,0.75*h);
static constexpr int N = 20;
if(mChecked){
double theta = -M_PI_4 * mAngle / 360;//在数学中,逆时针角度是正,在计算机中,y轴朝下,逆时针的角度为负数
double scale = 1 - (2-sqrt(2)/2)/2 / 360 * mAngle;
for(int i = 0 ;i <= N;++i){
double x = 0;
double y = -h/2/N * i;
auto x2 = scale * ( cos(theta) * x - sin(theta) * y);
auto y2 = scale * ( sin(theta) * x + cos(theta) * y);
painter.drawPoint(QPointF(x2,y2));
}
theta *= -1;
for(int i = 0;i <= N;++i){
double x = w/2/N*i;
double y = 0;
auto x2 = scale * ( cos(theta) * x - sin(theta) * y);
auto y2 = scale * ( sin(theta) * x + cos(theta) * y);
painter.drawPoint(QPointF(x2,y2));
}
painter.resetTransform();
painter.translate(0.75*w, 0.25*h);
theta = atan(2.0/3) * mAngle / 360;
scale = 1- (2-sqrt(3.25))/2 * mAngle / 360;
double dx = -0.125*w * mAngle / 360;
double dy = 0.25*h * mAngle / 360;
for(int i = 0;i <= N;i++){
double x = 0;
double y = 0.5*h/N * i;
auto x2 = scale * ( cos(theta) * x - sin(theta) * y) + dx;
auto y2 = scale * ( sin(theta) * x + cos(theta) * y) + dy;
painter.drawPoint(QPointF(x2,y2));
}
theta = -atan(1.5) * mAngle / 360;
dx *= -1;
dy = -0.125*h * mAngle / 360;
for(int i = 0;i <= N;i++){
double x = -0.5*w * i / N;
double y = 0;
auto x2 = scale * ( cos(theta) * x - sin(theta) * y) + dx;
auto y2 = scale * ( sin(theta) * x + cos(theta) * y) + dy;
painter.drawPoint(QPointF(x2,y2));
}
}
else{
double theta = M_PI_4 * mAngle / 360;
double scale = 1+ (2*sqrt(2) - 1) * mAngle / 360;
for(int i = 0 ;i <= N;++i){
double x = -0.125*w/N * i;
double y = -0.125*h/N * i;
auto x2 = scale * ( cos(theta) * x - sin(theta) * y);
auto y2 = scale * ( sin(theta) * x + cos(theta) * y);
painter.drawPoint(QPointF(x2,y2));
}
theta *= -1;
for(int i = 0 ;i <= N;++i){
double x = 0.125*w/N * i;
double y = 0.125*h/N * i;
auto x2 = scale * ( cos(theta) * x - sin(theta) * y);
auto y2 = scale * ( sin(theta) * x + cos(theta) * y);
painter.drawPoint(QPointF(x2,y2));
}
painter.resetTransform();
painter.translate(0.625*w, 0.5*h);
theta = -atan(2.0/3) * mAngle / 360;
scale = 1 + (2.0/sqrt(3.25) - 1) * mAngle / 360;
double dx = 0.125*w * mAngle / 360;
double dy = -0.25*h * mAngle / 360;
for(int i = 0;i <= N;i++){
double x = -0.25*w * i/N;
double y = 0.375*h * i / N;
auto x2 = scale * ( cos(theta) * x - sin(theta) * y) + dx;
auto y2 = scale * ( sin(theta) * x + cos(theta) * y) + dy;
painter.drawPoint(QPointF(x2,y2));
}
theta = atan(1.5) * mAngle / 360;
dx= -0.375*w * mAngle / 360;
dy = -0.25*h * mAngle / 360;
for(int i = 0;i <= N;i++){
double x = 0.25*w * i / N;
double y = -0.375*h * i / N;
auto x2 = scale * ( cos(theta) * x - sin(theta) * y) + dx;
auto y2 = scale * ( sin(theta) * x + cos(theta) * y) + dy;
painter.drawPoint(QPointF(x2,y2));
}
}
}
void CheckboxTransform::mouseReleaseEvent(QMouseEvent* e){
if(mAnim.state() == QAbstractAnimation::Running) return;
mChecked = !mChecked;
mAnim.setStartValue(0);
mAnim.setEndValue(360);
mAnim.start();
}
CheckboxBanner::CheckboxBanner(QWidget *parent){
setFixedSize(75,30);
mAnim.setDuration(300);
mAngle = 360;
}
void CheckboxBanner::paintEvent(QPaintEvent* e){
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(Qt::NoPen);
const int w = width();
const int h = height();
if(mChecked){
painter.setBrush(QBrush("lightgreen"));
}
else{
painter.setBrush(QBrush("gray"));
}
QPainterPath pp;
pp.moveTo(w/6,0);
pp.lineTo(w,0);
pp.lineTo(5.0/6*w,h);
pp.lineTo(0,h);
pp.lineTo(w/6,0);
pp.closeSubpath();
painter.drawPath(pp);
QPen pen("white");
pen.setWidth(4);
painter.setPen(pen);
painter.setFont(QFont("Microsoft YaHei",12));
if(mChecked){//move to left
painter.translate(w*(1 - sin(M_PI_2 * mAngle/360)),0);
painter.drawText(QRect(0,0,w,h),Qt::AlignCenter, "ON");
}
else{
painter.translate(w*(sin(M_PI_2 * mAngle/360) -1),0);
painter.drawText(QRect(0,0,w,h),Qt::AlignCenter, "OFF");
}
}
void CheckboxBanner::mouseReleaseEvent(QMouseEvent* e){
if(mAnim.state() == QAbstractAnimation::Running) return;
mChecked = !mChecked;
mAnim.setStartValue(0);
mAnim.setEndValue(360);
mAnim.start();
}
CheckboxMark::CheckboxMark(QWidget *parent){
setFixedSize(40,40);
mAnim.setDuration(300);
mAngle = 360;
}
void CheckboxMark::paintEvent(QPaintEvent* e){
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setBrush(Qt::NoBrush);
const int w = width();
const int h = height();
QPen pen;
pen.setWidth(2);
if(mChecked){
pen.setColor("lightgreen");
}
else{
pen.setColor("gray");
}
painter.setPen(pen);
painter.translate(0,0.2*h);
painter.drawRoundedRect(QRectF(0,0,0.8*w,0.8*h).adjusted(2,2,-2,-2),4,4);
painter.resetTransform();
painter.translate(0.125*w,0.5*h);
if(mChecked){
QPen pen("lightgreen");
pen.setWidth(6);
pen.setCapStyle(Qt::RoundCap);
pen.setJoinStyle(Qt::RoundJoin);
painter.setPen(pen);
if(mAngle <= 120){
int dw = 0.25*w * mAngle / 120;
int dh = 0.25*h * mAngle / 120;
painter.drawLine(0,0,dw,dh);
}
else{
painter.drawLine(0,0,0.25*w,0.25*h);
auto rat = (mAngle - 120) / 240.0;
painter.resetTransform();
painter.translate(0.375*w,0.75*h);
int dw = 0.5*w * rat;
int dh = 0.5*h * rat;
painter.drawLine(0,0,dw,-dh);
}
}
else{
}
}
void CheckboxMark::mouseReleaseEvent(QMouseEvent* e){
if(mAnim.state() == QAbstractAnimation::Running) return;
mChecked = !mChecked;
mAnim.setStartValue(0);
mAnim.setEndValue(360);
mAnim.start();
}