当前位置: 首页 > news >正文

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

话不多说,先上效果图

代码示例:

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

相关文章:

  • 谈谈 undefined 和 null
  • SAP(第四周)
  • NebulaGraph3.3.0部署与配置
  • 基于运动电商虚拟数据的商业洞察与分析
  • 【Mac】安装 Parallels Desktop、Windows、Rocky Linux
  • Windows 图形显示驱动开发-WDDM 3.0功能- 硬件翻转队列(一)
  • 【Json—RPC框架】:宏定义不受命名空间限制,续行符的错误使用造成的bug
  • 计算机组成原理试题六
  • 正则表达式:贪婪匹配与非贪婪匹配
  • [贪心算法] 摆动序列
  • 佰泰盛世公司推出最新低成本的DSP功放音箱解决方案
  • 仿RabbitMQ的消息队列
  • 数据集格式转换——json2txt、xml2txt、txt2json【复制就能用】
  • 专栏特辑--如何查询Essential Science Indicators (ESI)- 高被引论文--我的文章和高引文章的差距
  • ccfcsp3402矩阵重塑(其二)
  • 2025-03-18 学习记录--C/C++-PTA 习题4-9 打印菱形图案
  • Python 阶段一综合案例之质数判断算法
  • AGI大模型(8):提示词的安全与防护
  • 无人机吊舱模块更换技术难点分析!
  • Redis-锁-商品秒杀防止超卖
  • 国家主席习近平会见斯洛伐克总理菲佐
  • 1450亿元!财政部拟发行2025年中央金融机构注资特别国债(二期)
  • 经济日报整版聚焦“妈妈岗”:就业路越走越宽,有温度重实效
  • 公示!17个新职业、42个新工种亮相
  • 澎湃研究所“营商环境研究伙伴计划”启动
  • 万达电影:股东杭州臻希拟减持不超1.3927%公司股份