话不多说,先上效果图
代码示例:
#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);设置动画周期可改变水波速度