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

相关推荐
用户805533698032 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner2 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz7 天前
QML Hello World 入门示例
qt
xcyxiner10 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner11 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner11 天前
DicomViewer (添加模型类)3
qt
xcyxiner12 天前
DicomViewer (目录调整) 2
qt
xcyxiner12 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
桥田智能14 天前
桥田智能 QT-650S:面向白车身焊装的 800kg 重载快换解决方案
开发语言·qt·系统架构
森G14 天前
75、服务器源码解析---------云视频服务项目
linux·服务器·网络·c++·qt