QWidget实现开关按钮

1、开关按钮效果图

在这里插入图片描述

2、自定义开关按钮的实现

首先是使用Q_PROPERTY将开关按钮的属性注册到Qt的元对象系统重,方便后续将开关控件集成到QtDesigner设计师界面中:
在这里插入图片描述
如下是开关控件的属性:
在这里插入图片描述
在绘制时,首先将上面属性中的颜色初始化:
在这里插入图片描述
然后就是通过paintEvent这个绘图事件来进行绘制,首先绘制开关按钮的背景,它的背景是一个圆角矩形,然后是绘制内部的小椭圆,小椭圆的位置在背景的左侧,当然不是完全贴合,小椭圆与背景之间有外部边距,如下是代码实现:

void SwitchButton::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);

    QPainterPath path;
    QColor backsColor;
    QColor circlesColor;
    //设置选中和未被选的画笔颜色
    if(this->isEnabled())
    {
        if(checked)
        {
            backsColor = pressedColor;
            circlesColor = QColor(Qt::white);
        }
        else
        {
            backsColor = backgroundColor;
            circlesColor = circleColor;
        }
    }
    else
    {
        backsColor = backgroundColor;
        circlesColor = disabledColor;
    }

    //绘制外部大圆
    painter.setBrush(backsColor);
    path.addRoundedRect(QRectF(0,0,this->width(),this->height()),qMin(this->width(),this->height())/2,qMin(this->width(),this->height())/2);
    painter.drawPath(path.simplified());
    //绘制内圆
    painter.setBrush(circlesColor);
    painter.setOpacity(1.0);
    painter.drawEllipse(QRectF(margins + xPos, margins, height() - margins*2, height() - margins* 2));
}

绘制效果如下:
在这里插入图片描述
上面使用绘图事件只实现了静态的开关按钮,点击无反应,下面是通过鼠标点击事件和鼠标松开事件以及状态改变的函数来实现开关按钮点击后动态变化的效果:

//鼠标点击(左键点击)
void SwitchButton::mousePressEvent(QMouseEvent *event)
{
    if(this->isEnabled())
    {
        if(event->buttons() & Qt::LeftButton)
        {
            event->accept();
        }
        else
        {
            event->ignore();
        }
    }
}
//鼠标松开
void SwitchButton::mouseReleaseEvent(QMouseEvent *event)
{
    if(this->isEnabled() && this->isFinish())
    {
        if(event->type() == QMouseEvent::MouseButtonRelease && event->button() == Qt::LeftButton)
        {
            event->accept();
            checked =! checked; //改变状态
            changeState(checked);//状态改变后,更改动画效果
            emit toggled(checked);
        }
        else
        {
            event->ignore();
        }
    }
}

//状态改变函数
void SwitchButton::changeState(bool state)
{
    if(state)
    {
        proAnimation->setStartValue(0);
        proAnimation->setEndValue(this->width()-this->height());
    }
    else
    {
        proAnimation->setStartValue(this->width()-this->height());
        proAnimation->setEndValue(0);
    }
    proAnimation->start();
}

3、完整代码

SwitchButton.h如下:

#ifndef SWITCHBUTTON_H
#define SWITCHBUTTON_H

#include <QWidget>
#include<QPainter>
#include<QMouseEvent>
#include<QPropertyAnimation>
#include<QResizeEvent>
#include<QtMath>

class SwitchButton : public QWidget
{
    Q_OBJECT
public:
    explicit SwitchButton(QWidget *parent = nullptr);
    //将属性注册到元对象系统中
    Q_PROPERTY(QColor backgroundColor READ getBackColor WRITE setBackColor)
    Q_PROPERTY(QColor pressedColor READ getPressedColor WRITE setPressedColor)
    Q_PROPERTY(QColor disabledColor READ getDisabledColor WRITE setDisabledColor)
    Q_PROPERTY(QColor circleColor READ getCircleColor WRITE setCircleColor)
    Q_PROPERTY(qreal xPos READ getXPos WRITE setXPos)

public:
    bool isToggled()const;
    void setToggled(bool checked);
    void setBackColor(QColor color);
    QColor getBackColor();
    void setPressedColor(QColor color);
    QColor getPressedColor();
    void setDisabledColor(QColor color);
    QColor getDisabledColor();
    void setCircleColor(QColor color);
    QColor getCircleColor();
    void setXPos(qreal xPos);
    qreal getXPos();
    void changeState(bool state);
    bool isFinish() const;

protected:
    virtual void paintEvent(QPaintEvent *event) override;
    virtual void mousePressEvent(QMouseEvent *event) override;
    virtual void mouseReleaseEvent(QMouseEvent *event) override;
    void resizeEvent(QResizeEvent *event) override;

signals:
    void toggled(bool checked);

private:
    QColor                   backgroundColor;  //背景颜色
    QColor                   pressedColor;     //点击时的背景颜色
    QColor                   disabledColor;    //无法选中的背景颜色
    QColor                   circleColor;      //小椭圆的颜色
    qreal                    xPos;              //小椭圆在背景上面的x轴的运动路径
    bool                     checked;          //是否选中小椭圆
    int                      margins;          //外边距
    QPropertyAnimation*      proAnimation;     //动画对象
};

#endif // SWITCHBUTTON_H

Switch.cpp如下:

#include "switchbutton.h"

SwitchButton::SwitchButton(QWidget *parent) : QWidget(parent),
    backgroundColor(247,245,241),
    pressedColor(26,118,197),
    disabledColor(190,190,190),
    circleColor(93,93,93),
    checked(false),
    margins(5)
{
    this->setCursor(Qt::PointingHandCursor);
    this->resize(400,200);

    proAnimation = new QPropertyAnimation(this,"xPos");
    proAnimation->setDuration(300);
    proAnimation->setLoopCount(1);
}

bool SwitchButton::isToggled() const
{
    return this->checked;
}

void SwitchButton::setToggled(bool checked)
{
    if(this->checked == checked)
    {
        return;
    }
    this->checked = checked;
    changeState(this->checked);
}

void SwitchButton::setBackColor(QColor color)
{
    this->backgroundColor = color;
}

QColor SwitchButton::getBackColor()
{
    return this->backgroundColor;
}

void SwitchButton::setPressedColor(QColor color)
{
    this->pressedColor = color;
}

QColor SwitchButton::getPressedColor()
{
    return this->pressedColor;
}

void SwitchButton::setDisabledColor(QColor color)
{
    this->disabledColor = color;
}

QColor SwitchButton::getDisabledColor()
{
    return this->disabledColor;
}

void SwitchButton::setCircleColor(QColor color)
{
    this->circleColor = color;
}

QColor SwitchButton::getCircleColor()
{
    return this->circleColor;
}

void SwitchButton::setXPos(qreal xPos)
{
    this->xPos = xPos;
    update();
}

qreal SwitchButton::getXPos()
{
    return this->xPos;
}

void SwitchButton::changeState(bool state)
{
    if(state)
    {
        proAnimation->setStartValue(0);
        proAnimation->setEndValue(this->width()-this->height());
    }
    else
    {
        proAnimation->setStartValue(this->width()-this->height());
        proAnimation->setEndValue(0);
    }
    proAnimation->start();
}

bool SwitchButton::isFinish() const
{
    return proAnimation->state() == QAbstractAnimation::Stopped;
}

void SwitchButton::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);

    QPainterPath path;
    QColor backsColor;
    QColor circlesColor;
    //设置选中和未被选的画笔颜色
    if(this->isEnabled())
    {
        if(checked)
        {
            backsColor = pressedColor;
            circlesColor = QColor(Qt::white);
        }
        else
        {
            backsColor = backgroundColor;
            circlesColor = circleColor;
        }
    }
    else
    {
        backsColor = backgroundColor;
        circlesColor = disabledColor;
    }

    //绘制外部大圆
    painter.setBrush(backsColor);
    path.addRoundedRect(QRectF(0,0,this->width(),this->height()),qMin(this->width(),this->height())/2,qMin(this->width(),this->height())/2);
    painter.drawPath(path.simplified());
    //绘制内圆
    painter.setBrush(circlesColor);
    painter.setOpacity(1.0);
    painter.drawEllipse(QRectF(margins + xPos, margins, height() - margins*2, height() - margins* 2));
}

void SwitchButton::mousePressEvent(QMouseEvent *event)
{
    if(this->isEnabled())
    {
        if(event->buttons() & Qt::LeftButton)
        {
            event->accept();
        }
        else
        {
            event->ignore();
        }
    }
}

void SwitchButton::mouseReleaseEvent(QMouseEvent *event)
{
    if(this->isEnabled() && this->isFinish())
    {
        if(event->type() == QMouseEvent::MouseButtonRelease && event->button() == Qt::LeftButton)
        {
            event->accept();
            checked =! checked; //改变状态
            changeState(checked);//状态改变后,更改动画效果
            emit toggled(checked);
        }
        else
        {
            event->ignore();
        }
    }
}

void SwitchButton::resizeEvent(QResizeEvent *event)
{
    this->xPos = checked ? this->width() - this->height() : 0;
    QWidget::resizeEvent(event);
}

4、将开关按钮集成到QtDesigner中

首先查看Qt基于哪种编译器:
在这里插入图片描述
然后选择Qt4设计师自定义控件。
在这里插入图片描述
然后是选择项目名称和位置,注意不要有中文路径。
在这里插入图片描述
选择上面的msvc2017 32bit的编译套件。
在这里插入图片描述
自定义控件名称,注意首字母大写。
在这里插入图片描述
设置开关按钮属于哪个组类。
在这里插入图片描述
最后点击完成即可。
Qt自动生成控件相关的文件:
在这里插入图片描述
将上面的开关按钮的代码拷贝到swichbutton.h和switchbutton.cpp中,使用Release模式编译生成。然后再release文件夹下找到开关按钮的dll文件:
在这里插入图片描述
最后将它拷贝到如下Qt的designer目录下:
在这里插入图片描述
最后随便创建一个qt项目,然后在ui文件中可以发现开关按钮:
在这里插入图片描述
它的属性也同样在ui界面可以修改(通过Q_PROPERTY将属性注册到qt元对象系统):
在这里插入图片描述
但点击运行项目时会出错:
在这里插入图片描述
原因很简单,因为我们没有包含它的头文件和源文件,将头文件和源文件复制到项目中,即可:
在这里插入图片描述
然后再pro文件中添加如下语句:
在这里插入图片描述
最后运行成功,效果如下:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值