Qt 实现波浪填充的圆形进度显示

发布于:2025-03-16 ⋅ 阅读:(10) ⋅ 点赞:(0)

话不多说,先上效果图

代码示例:

#include <QApplication>
#include <QWidget>
#include <QPainter>
#include <QPropertyAnimation>
#include <QTimer>
#include <cmath>

class WaveProgressBar : public QWidget
{
    Q_OBJECT
    Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged)
    Q_PROPERTY(qreal wavePhase READ wavePhase WRITE setWavePhase)
public:
    explicit WaveProgressBar(QWidget *parent = nullptr)
        : QWidget(parent), m_min(0), m_max(100), m_value(0),
          m_wavePhase(0), m_waveAmplitude(10), m_waveLength(150),
          m_waveColor(QColor(100, 180, 255))
    {
        //设置无边框和背景透明
        //setWindowFlags(windowFlags() |  Qt::FramelessWindowHint | Qt::Tool);
        //setAttribute(Qt::WA_TranslucentBackground);
        // 波浪相位动画
        QPropertyAnimation *waveAnim = new QPropertyAnimation(this, "wavePhase");
        waveAnim->setDuration(1000);
        waveAnim->setStartValue(0);
        waveAnim->setEndValue(m_waveLength);
        waveAnim->setLoopCount(-1);
        waveAnim->start();

        setMinimumSize(150, 150);
        resize(150, 150);
    }

    int value() const { return m_value; }
    qreal wavePhase() const { return m_wavePhase; }

    void setValue(int value)
    {
        value = qBound(m_min, value, m_max);
        if (m_value != value) {
            m_value = value;
            update();
            emit valueChanged(m_value);
        }
    }

    void setWavePhase(qreal phase)
    {
        m_wavePhase = phase;
        update();
    }

    void setWaveColor(const QColor &color)
    {
        m_waveColor = color;
        update();
    }

    void setWaveAmplitude(const qreal amplitude)
    {
        m_waveAmplitude = amplitude;
    }

signals:
    void valueChanged(int value);

protected:
    void paintEvent(QPaintEvent *) override
    {
        QPainter painter(this);
        painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);

        const qreal side = qMin(width(), height());
        const QRectF rect(0, 0, side, side);
        const QPointF center = rect.center();
        const qreal radius = side / 2.0;

        // 计算填充进度
        const qreal progress = (m_value - m_min) / static_cast<qreal>(m_max - m_min);
        const qreal fillHeight = rect.height() * (1 - progress);

        // 创建统一背景(使用波浪颜色的深色版本)
        painter.setPen(Qt::NoPen);
        painter.setBrush(m_waveColor.darker(150));
        painter.drawEllipse(center, radius, radius);

        // 创建波浪路径(始终覆盖整个圆形)
        QPainterPath wavePath;
        const qreal waterLevel = fillHeight;
        const qreal baseY = rect.top() + waterLevel;

        wavePath.moveTo(rect.left() - m_waveLength, baseY);

        // 生成波浪曲线
        for (qreal x = rect.left() - m_waveLength; x < rect.right() + m_waveLength; x += 1.0) {
            const qreal phase = (x + m_wavePhase) * M_PI / (m_waveLength / 2.0);
            const qreal y = baseY + m_waveAmplitude * sin(phase);
            wavePath.lineTo(x, y);
        }

        // 闭合路径形成填充区域
        wavePath.lineTo(rect.bottomRight() + QPointF(m_waveLength, 0));
        wavePath.lineTo(rect.bottomLeft() - QPointF(m_waveLength, 0));
        wavePath.closeSubpath();

        // 创建圆形裁剪路径,控制波浪在圆形区域内
        QPainterPath clipPath;
        clipPath.addEllipse(center, radius, radius);
        painter.setClipPath(clipPath);

        // 绘制渐变波浪
        QLinearGradient gradient(rect.topLeft(), rect.bottomLeft());
        gradient.setColorAt(0, m_waveColor.lighter(120));
        gradient.setColorAt(1, m_waveColor.darker(120));

        painter.setBrush(gradient);
        painter.drawPath(wavePath);

        // 绘制中心文本
        painter.setPen(Qt::white);
        painter.setFont(QFont("Arial", radius * 0.35, QFont::Bold));
        painter.drawText(rect, Qt::AlignCenter, QString::number(progress * 100, 'f', 0) + "%");
    }

private:
    int m_min;
    int m_max;
    int m_value;
    qreal m_wavePhase;
    qreal m_waveAmplitude; //波浪振幅
    qreal m_waveLength;    //波浪长度
    QColor m_waveColor;
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    static int value = 0;
    WaveProgressBar progressBar;
    progressBar.show();
    QTimer timer;
    QObject::connect(&timer, &QTimer::timeout, &progressBar, [&progressBar](){ progressBar.setValue(++value);  });
    timer.start(1000);

    return a.exec();
}

#include "main.moc"

具体实现效果可自由调整,
m_waveColor代表波浪颜色,示例代码改变m_waveColor亮度绘制背景,可自由修改。
水波效果由波长和振幅控制 “大振幅+长波长=平缓波浪”, “小振幅+短波长=密集波纹”。

通过 waveAnim->setDuration(1000);设置动画周期可改变水波速度