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

话不多说,先上效果图

代码示例:

cpp 复制代码
#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);设置动画周期可改变水波速度

相关推荐
赵民勇19 小时前
Qt QML中Component模块详解
qt
不会c嘎嘎21 小时前
QT中的常用控件 (三)
开发语言·qt
闫有尽意无琼21 小时前
Qt局部变量“遮蔽(shadow)”成员变量导致lambda传参报错
开发语言·qt
寻找华年的锦瑟21 小时前
Qt-YOLO-OpenCV
qt·opencv·yolo
南桥几晴秋21 小时前
Qt显示类控件
开发语言·c++·qt
_OP_CHEN21 小时前
【从零开始的Qt开发指南】(十八)Qt 事件进阶:定时器、事件分发器与事件过滤器的实战宝典
qt·前端开发·事件过滤器·qt事件·gui开发·qt定时器·事件分发器
晨风先生21 小时前
打包Qt程序的脚本package.bat
开发语言·qt
环黄金线HHJX.21 小时前
《QuantumTuan ⇆ QT:Qt》
人工智能·qt·算法·编辑器·量子计算
环黄金线HHJX.1 天前
拼音字母量子编程PQLAiQt架构”这一概念。结合上下文《QuantumTuan ⇆ QT:Qt》
开发语言·人工智能·qt·编辑器·量子计算
abcd_zjq1 天前
VS2022+QT6.9配置ONNXruntime GPU、CUDA、cuDNN(附官网下载链接)(GPU开启代码示例)
qt·visual studio·cuda·onnx