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);设置动画周期可改变水波速度

相关推荐
sycmancia8 小时前
Qt——编辑交互功能的实现
开发语言·qt
qq_4017004113 小时前
Qt 项目中使用 QSS 的全面总结
开发语言·qt
小短腿的代码世界14 小时前
信号路由风暴:Qt算法交易系统的高频信号分发架构
qt·算法·架构
郝学胜-神的一滴16 小时前
Qt 高级开发 010: 从跨界面传值到自定义信号
开发语言·c++·qt·程序人生·用户界面
Hua-Jay19 小时前
OpenCV联合C++/Qt 学习笔记(二十三)----图像校正及单目位姿估计
c++·笔记·qt·opencv·学习·计算机视觉
mirror_zAI20 小时前
C++ 仿 QQ 聊天室项目:Qt 客户端 + epoll 服务端 + Reactor 架构(含源码)
c++·qt·架构
Hua-Jay21 小时前
OpenCV联合C++/Qt 学习笔记(二十四)----差值法检测移动物体、稠密光流法跟踪移动物体及稀疏光流法跟踪移动物体
c++·笔记·qt·opencv·学习·计算机视觉
我在人间贩卖青春1 天前
重学Qt——对话框和多窗口程序设计
qt
努力努力再努力wz1 天前
【QT入门系列】QWidget 六大常用属性详解:windowOpacity、cursor、font、focus、toolTip 与 styleSheet
android·开发语言·数据结构·c++·qt·mysql·算法
程序leo源2 天前
Qt窗口详解
开发语言·数据库·c++·qt·青少年编程·c#