Qt水波进度条Demo

多谢飞扬青春的博客,看到水波形进度条的效果觉得非常不错,于是自己也模仿着做了一个类似的,效果图:



原理:

利用正弦曲线产生平滑曲线点集合,然后用大路径减去当前进度路径,形成水波效果。 


源码如下:

#ifndef SPROGRESSBAR_H
#define SPROGRESSBAR_H

#include <QWidget>
#include <QPainter>
#include <QtMath>

class SProgressBar : public QWidget
{
    Q_OBJECT
public:
    explicit SProgressBar(QWidget *parent = 0);

    enum PercentStyle_Type{
        PercentStyle_Rect = 0,//矩形
        PercentStyle_Circle,//圆
        PercentStyle_Ellipse,//椭圆
    };

    void setValue(int value) {m_value = value;}
    int value() {return m_value;}

    void setMaxValue(int value) {m_maxValue = value;}
    int maxValue() {return m_maxValue;}

    void setMinValue(int value) {m_minValue = value;}
    int minValue() {return m_minValue;}

    void setPercentStyle(SProgressBar::PercentStyle_Type type) {m_percentStyle = type;}
    PercentStyle_Type percentStyle() {return m_percentStyle;}

    void setWaterDensity(int val) {m_waterDensity = val;}
    int waterDensity() {return m_waterDensity;}

    void setColor(QColor col) {m_usedColor = col;}
    QColor color() {return m_usedColor;}

    void setWaterHeight(double val) {m_waterHeight = val;}
    double waterHeight() {return m_waterHeight;}

    void setBorderWidth(int val) {m_borderWidth = val;}
    int borderWidth() {return m_borderWidth;}

    void setTextColor(QColor col) {m_textColor = col;}
    QColor textColor() {return m_textColor;}

    void setBoderColor(QColor col) {m_boderColor = col;}
    QColor boderColor() {return m_boderColor;}

    void setBgColor(QColor col) {m_bgColor = col;}
    QColor bgColor() {return m_bgColor;}
protected:
    void paintEvent(QPaintEvent *event);
    void timerEvent(QTimerEvent *event);
private:
    PercentStyle_Type m_percentStyle = PercentStyle_Rect;
    QColor m_usedColor = QColor(180,255,255);
    QColor m_textColor = Qt::white;
    QColor m_boderColor = Qt::black;
    QColor m_bgColor = Qt::gray;
    QFont m_font;
    int m_value = 80;
    int m_minValue = 0;
    int m_maxValue = 100;
    int m_waterDensity = 10; // 水波的密度
    double m_waterHeight = 0.03;
    double m_offset = 50;
    int m_borderWidth = 10;
};

#endif // SPROGRESSBAR_H

#include "sprogressbar.h"

SProgressBar::SProgressBar(QWidget *parent) : QWidget(parent)
{
    m_font.setFamily("Microsoft YaHei");
    this->startTimer(80);
}

void SProgressBar::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);  // 反锯齿;
    int height = this->height();
    int width = this->width();
    int side = qMin(width, height);

    //计算当前值所占百分比
    double percent = 1 - (double)(m_value - m_minValue) / (m_maxValue - m_minValue);

    //正弦曲线公式 y = A * sin(ωx + φ) + k
    //w表示周期,可以理解为水波的密度,值越大密度越大(浪越密集 ^_^),取值 密度*M_PI/宽度
    double w = m_waterDensity * M_PI / width;
    //A表示振幅,可以理解为水波的高度,值越大高度越高(越浪 ^_^),取值高度的百分比
    double A = height * m_waterHeight;
    //k表示y轴偏移,可以理解为进度,取值高度的进度百分比
    double k = height * percent;

    //第一条波浪路径集合
    QPainterPath waterPath1;
    //第二条波浪路径集合
    QPainterPath waterPath2;

    //移动到左上角起始点
    waterPath1.moveTo(0, height);
    waterPath2.moveTo(0, height);

    m_offset += 0.6;
    if (m_offset > (width / 2)) {
        m_offset = 0;
    }

    for(int x = 0; x <= width; x++) {
        //第一条波浪Y轴
        double waterY1 = (double)(A * sin(w * x + m_offset)) + k;

        //第二条波浪Y轴
        double waterY2 = (double)(A * sin(w * x + m_offset + (width / 2 * w))) + k;

        //如果当前值为最小值则Y轴为高度
        if (m_value == m_minValue) {
            waterY1 = height;
            waterY2 = height;
        }

        //如果当前值为最大值则Y轴为0
        if (m_value == m_maxValue) {
            waterY1 = 0;
            waterY2 = 0;
        }

        waterPath1.lineTo(x, waterY1);
        waterPath2.lineTo(x, waterY2);
    }

    //移动到右下角结束点,整体形成一个闭合路径
    waterPath1.lineTo(width, height);
    waterPath2.lineTo(width, height);

    //大路径
    QPainterPath bigPath;
    if (m_percentStyle == PercentStyle_Rect) {
        width = width - m_borderWidth * 2;
        height = height - m_borderWidth * 2;
        bigPath.addRect(m_borderWidth, m_borderWidth, width, height);
        painter.setBrush(m_boderColor);
        painter.drawRect(this->rect());
        painter.setBrush(m_bgColor);
        painter.drawRect(m_borderWidth, m_borderWidth, width, height);
    } else if (m_percentStyle == PercentStyle_Circle) {
        painter.setBrush(m_boderColor);
        painter.drawEllipse((width - side) / 2, (height - side) / 2, side, height);
        side = side - m_borderWidth * 2;
        bigPath.addEllipse((width - side) / 2, m_borderWidth, side, side);
        painter.setBrush(m_bgColor);
        painter.drawEllipse((width - side) / 2, m_borderWidth, side, side);
    } else if (m_percentStyle == PercentStyle_Ellipse) {
        width = width - m_borderWidth * 2;
        height = height - m_borderWidth * 2;
        bigPath.addEllipse(m_borderWidth, m_borderWidth, width, height);
        painter.setBrush(m_boderColor);
        painter.drawEllipse(this->rect());
        painter.setBrush(m_bgColor);
        painter.drawEllipse(m_borderWidth, m_borderWidth, width, height);
    }

    painter.save();

    //新路径,用大路径减去波浪区域的路径,形成遮罩效果
    QPainterPath path;
    painter.setPen(Qt::NoPen);
    QColor waterColor1 = m_usedColor;
    waterColor1.setAlpha(100);
    QColor waterColor2 = m_usedColor;
    waterColor2.setAlpha(180);

    //第一条波浪挖去后的路径
    path = bigPath.intersected(waterPath1);
    painter.setBrush(waterColor1);
    painter.drawPath(path);

    //第二条波浪挖去后的路径
    path = bigPath.intersected(waterPath2);
    painter.setBrush(waterColor2);
    painter.drawPath(path);

    painter.restore();

    //绘制文字
    m_font.setPixelSize(this->width()/4);
    painter.setPen(m_textColor);
    painter.setFont(m_font);
    painter.drawText(this->rect(), Qt::AlignCenter, QString("%0%").arg(QString::number(m_value)));
}

void SProgressBar::timerEvent(QTimerEvent *event)
{
    Q_UNUSED(event);
    this->update();
}


#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QPainter>
#include <QLabel>
#include <QSlider>
#include <QComboBox>
#include <QPushButton>
#include "sprogressbar.h"

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);
    void initUI();
private slots:
    void onValueChanged(int value);
    void onPercentStyle(int type);
    void onWaterDesity(int value);
    void onColorClicked();
    void onWaterHeight(int value);
    void onBorderWidth(int value);
    void onTextColorClicked();
    void onBoderColorClicked();
    void onBgColorClicked();
private:
    SProgressBar *m_progressBar = Q_NULLPTR;
    QLabel* m_valueLab = Q_NULLPTR;
    QSlider* m_valueSlider = Q_NULLPTR;
    QLabel* m_percentStyleLab = Q_NULLPTR;
    QComboBox* m_percentStyleComboBox = Q_NULLPTR;
    QLabel* m_waterDesityLab = Q_NULLPTR;
    QSlider* m_waterDesitySlider = Q_NULLPTR;
    QLabel* m_colorLab = Q_NULLPTR;
    QPushButton* m_colorBtn = Q_NULLPTR;
    QLabel* m_waterHeightLab = Q_NULLPTR;
    QSlider* m_waterHeightSlider = Q_NULLPTR;
    QLabel* m_borderWidthLab = Q_NULLPTR;
    QSlider* m_borderWidthSlider = Q_NULLPTR;
    QLabel* m_textColorLab = Q_NULLPTR;
    QPushButton* m_textColorBtn = Q_NULLPTR;
    QLabel* m_boderColorLab = Q_NULLPTR;
    QPushButton* m_boderColorBtn = Q_NULLPTR;
    QLabel* m_bgColorLab = Q_NULLPTR;
    QPushButton* m_bgColorBtn = Q_NULLPTR;
};

#endif // WIDGET_H

#include "widget.h"
#include <QColorDialog>
#include <QIcon>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    this->setWindowIcon(QIcon(":/Demo_Hello.ico"));
    this->setWindowTitle("水波纹Demo");
    initUI();
}

void Widget::initUI()
{
    this->setFixedSize(900,500);
    m_progressBar = new SProgressBar(this);
    m_progressBar->resize(600,500);
    m_progressBar->move(0,0);
    m_valueLab = new QLabel(this);
    m_valueLab->setAlignment(Qt::AlignCenter);
    m_valueLab->resize(100,30);
    m_valueLab->move(600,0);
    m_valueLab->setText("\350\277\233\345\272\246"); // 进度
    m_valueSlider = new QSlider(this);
    m_valueSlider->setOrientation(Qt::Horizontal);
    m_valueSlider->resize(180,20);
    m_valueSlider->move(700,5);
    m_valueSlider->setMaximum(m_progressBar->maxValue());
    m_valueSlider->setMinimum(m_progressBar->minValue());
    m_valueSlider->setValue(m_progressBar->value());
    connect(m_valueSlider, SIGNAL(valueChanged(int)), this, SLOT(onValueChanged(int)));
    m_percentStyleLab = new QLabel(this);
    m_percentStyleLab->setAlignment(Qt::AlignCenter);
    m_percentStyleLab->resize(100,30);
    m_percentStyleLab->move(600,40);
    m_percentStyleLab->setText("\345\275\242\347\212\266"); // 形状
    m_percentStyleComboBox = new QComboBox(this);
    m_percentStyleComboBox->resize(180,30);
    m_percentStyleComboBox->move(700,40);
    m_percentStyleComboBox->addItem("\347\237\251\345\275\242"); // 矩形
    m_percentStyleComboBox->addItem("\345\234\206\345\275\242"); // 圆形
    m_percentStyleComboBox->addItem("\346\244\255\345\234\206"); // 椭圆
    m_percentStyleComboBox->setCurrentIndex(m_progressBar->percentStyle());
    connect(m_percentStyleComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onPercentStyle(int)));
    m_waterDesityLab = new QLabel(this);
    m_waterDesityLab->setAlignment(Qt::AlignCenter);
    m_waterDesityLab->resize(100,30);
    m_waterDesityLab->move(600,80);
    m_waterDesityLab->setText("\346\260\264\346\263\242\347\232\204\345\257\206\345\272\246"); // 水波的密度
    m_waterDesitySlider = new QSlider(this);
    m_waterDesitySlider->setOrientation(Qt::Horizontal);
    m_waterDesitySlider->resize(180,20);
    m_waterDesitySlider->move(700,85);
    m_waterDesitySlider->setMaximum(100);
    m_waterDesitySlider->setMinimum(0);
    m_waterDesitySlider->setValue(m_progressBar->waterDensity());
    connect(m_waterDesitySlider, SIGNAL(valueChanged(int)), this, SLOT(onWaterDesity(int)));
    m_colorLab = new QLabel(this);
    m_colorLab->setAlignment(Qt::AlignCenter);
    m_colorLab->resize(100,30);
    m_colorLab->move(600,120);
    m_colorLab->setText("\350\203\214\346\231\257\351\242\234\350\211\262"); // 背景颜色
    m_colorBtn = new QPushButton(this);
    m_colorBtn->resize(180,20);
    m_colorBtn->move(700,125);
    QString styleCol = QString("background-color:rgb(%0,%1,%2)").arg(m_progressBar->color().red())
            .arg(m_progressBar->color().green()).arg(m_progressBar->color().blue());
    m_colorBtn->setStyleSheet(styleCol);
    connect(m_colorBtn, SIGNAL(clicked(bool)),this, SLOT(onColorClicked()));
    m_waterHeightLab = new QLabel(this);
    m_waterHeightLab->setAlignment(Qt::AlignCenter);
    m_waterHeightLab->resize(100,30);
    m_waterHeightLab->move(600,160);
    m_waterHeightLab->setText("\346\260\264\347\232\204\351\253\230\345\272\246"); // 水的高度
    m_waterHeightSlider = new QSlider(this);
    m_waterHeightSlider->setOrientation(Qt::Horizontal);
    m_waterHeightSlider->resize(180,20);
    m_waterHeightSlider->move(700,165);
    m_waterHeightSlider->setMaximum(100);
    m_waterHeightSlider->setMinimum(0);
    m_waterHeightSlider->setValue(m_progressBar->waterHeight()*1000);
    connect(m_waterHeightSlider, SIGNAL(valueChanged(int)), this, SLOT(onWaterDesity(int)));
    m_borderWidthLab = new QLabel(this);
    m_borderWidthLab->setAlignment(Qt::AlignCenter);
    m_borderWidthLab->resize(100,30);
    m_borderWidthLab->move(600,200);
    m_borderWidthLab->setText("\350\276\271\346\241\206\345\256\275\345\272\246"); // 边框宽度
    m_borderWidthSlider = new QSlider(this);
    m_borderWidthSlider->setOrientation(Qt::Horizontal);
    m_borderWidthSlider->resize(180,20);
    m_borderWidthSlider->move(700,205);
    m_borderWidthSlider->setMaximum(20);
    m_borderWidthSlider->setMinimum(0);
    m_borderWidthSlider->setValue(m_progressBar->borderWidth());
    connect(m_borderWidthSlider, SIGNAL(valueChanged(int)), this, SLOT(onBorderWidth(int)));
    m_textColorLab = new QLabel(this);
    m_textColorLab->setAlignment(Qt::AlignCenter);
    m_textColorLab->resize(100,30);
    m_textColorLab->move(600,240);
    m_textColorLab->setText("\345\255\227\344\275\223\351\242\234\350\211\262"); // 字体颜色
    m_textColorBtn = new QPushButton(this);
    m_textColorBtn->resize(180,20);
    m_textColorBtn->move(700,245);
    QString textCol = QString("background-color:rgb(%0,%1,%2)").arg(m_progressBar->textColor().red())
            .arg(m_progressBar->textColor().green()).arg(m_progressBar->textColor().blue());
    m_textColorBtn->setStyleSheet(textCol);
    connect(m_textColorBtn, SIGNAL(clicked(bool)),this, SLOT(onTextColorClicked()));
    m_boderColorLab = new QLabel(this);
    m_boderColorLab->setAlignment(Qt::AlignCenter);
    m_boderColorLab->resize(100,30);
    m_boderColorLab->move(600,280);
    m_boderColorLab->setText("\350\276\271\346\241\206\351\242\234\350\211\262"); // 边框颜色
    m_boderColorBtn = new QPushButton(this);
    m_boderColorBtn->resize(180,20);
    m_boderColorBtn->move(700,285);
    QString boderCol = QString("background-color:rgb(%0,%1,%2)").arg(m_progressBar->boderColor().red())
            .arg(m_progressBar->boderColor().green()).arg(m_progressBar->boderColor().blue());
    m_boderColorBtn->setStyleSheet(boderCol);
    connect(m_boderColorBtn, SIGNAL(clicked(bool)),this, SLOT(onBoderColorClicked()));
    m_bgColorLab = new QLabel(this);
    m_bgColorLab->setAlignment(Qt::AlignCenter);
    m_bgColorLab->resize(100,30);
    m_bgColorLab->move(600,320);
    m_bgColorLab->setText("\346\234\252\345\241\253\345\205\205\351\242\234\350\211\262"); // 未填充颜色
    m_bgColorBtn = new QPushButton(this);
    m_bgColorBtn->resize(180,20);
    m_bgColorBtn->move(700,325);
    QString bgCol = QString("background-color:rgb(%0,%1,%2)").arg(m_progressBar->bgColor().red())
            .arg(m_progressBar->bgColor().green()).arg(m_progressBar->bgColor().blue());
    m_bgColorBtn->setStyleSheet(bgCol);
    connect(m_bgColorBtn, SIGNAL(clicked(bool)),this, SLOT(onBgColorClicked()));
}

void Widget::onValueChanged(int value)
{
    m_progressBar->setValue(value);
}

void Widget::onPercentStyle(int type)
{
    SProgressBar::PercentStyle_Type index = SProgressBar::PercentStyle_Type(type);
    m_progressBar->setPercentStyle(index);
}

void Widget::onWaterDesity(int value)
{
    m_progressBar->setWaterDensity(value);
}

void Widget::onColorClicked()
{
    QColor c = QColorDialog::getColor(m_progressBar->color());
    if(c.isValid()) {
        m_progressBar->setColor(c);
        QString styleCol = QString("background-color:rgb(%0,%1,%2)").arg(c.red()).arg(c.green()).arg(c.blue());
        m_colorBtn->setStyleSheet(styleCol);
    }
}

void Widget::onWaterHeight(int value)
{
    m_progressBar->setWaterHeight(double(value/1000.0));
}

void Widget::onBorderWidth(int value)
{
    m_progressBar->setBorderWidth(value);
}

void Widget::onTextColorClicked()
{
    QColor c = QColorDialog::getColor(m_progressBar->textColor());
    if(c.isValid()) {
        m_progressBar->setTextColor(c);
        QString styleCol = QString("background-color:rgb(%0,%1,%2)").arg(c.red()).arg(c.green()).arg(c.blue());
        m_textColorBtn->setStyleSheet(styleCol);
    }
}

void Widget::onBoderColorClicked()
{
    QColor c = QColorDialog::getColor(m_progressBar->boderColor());
    if(c.isValid()) {
        m_progressBar->setBoderColor(c);
        QString styleCol = QString("background-color:rgb(%0,%1,%2)").arg(c.red()).arg(c.green()).arg(c.blue());
        m_boderColorBtn->setStyleSheet(styleCol);
    }
}

void Widget::onBgColorClicked()
{
    QColor c = QColorDialog::getColor(m_progressBar->bgColor());
    if(c.isValid()) {
        m_progressBar->setBgColor(c);
        QString styleCol = QString("background-color:rgb(%0,%1,%2)").arg(c.red()).arg(c.green()).arg(c.blue());
        m_bgColorBtn->setStyleSheet(styleCol);
    }
}



©️2020 CSDN 皮肤主题: 代码科技 设计师:Amelia_0503 返回首页