zoukankan      html  css  js  c++  java
  • Qt QProgressBar美化,水波纹进度条

    首先上实例

    要模拟波浪,就要首先画出一条波浪线,正弦余弦曲线就很适合。 

    y=A*sin(ω*x+φ)+k

    y=A*cos(ω*x+φ)+k

    这是正弦余弦曲线的公式,要想实现水波效果,那需要两条曲线,一条曲线的波峰对着另外一条曲线的波谷,要实现这样的曲线效果,只有让正弦曲线前移π/2个单位。所以我们最后对两个水波使用的公式就变成了下面两个

    y=A*sin(ω*x-π/2+φ)+k

    y=A*cos(ω*x+φ)+k

    在我们的代码中A就是水波的高度,ω是水波的周期,φ是水波的偏移量,用于实现动画效果,k是水波的高度,注意由于我们的电脑坐标系是以左上角为原点,这和我们高中坐标系理解的不同,所以这里水波的高度是要进行一段处理的。

    下面直接上代码

    #include <QProgressBar>
    #include <QTimer>
    #include <QPainter>
    #include <QColor>
    #include <QtMath>
    class WaterProgressBar : public QProgressBar
    {
        Q_OBJECT
    
    public:
        WaterProgressBar(QWidget *parent);
        ~WaterProgressBar();
    
    protected:
        //页面重绘事件
        void paintEvent(QPaintEvent *event);
    private:
        void drawBackGround(QPainter* painter);
        void drawWaterWave(QPainter* painter);
        void drawText(QPainter* painter);
    
    private:
        int m_iBorderWidth;//边框厚度
        int m_iValue;//当前进度条进度
        double m_dOffset;//水波偏移量
        QColor m_waterColor;//水波颜色
        QColor m_backgroundColor;//背景颜色
        QColor m_borderColor;//边框颜色
        QColor m_textColor;//文本颜色
        QTimer *m_timer;//控制水波移动的定时器
    };
    #include "stdafx.h"
    #include "WaterProgressBar.h"
    
    WaterProgressBar::WaterProgressBar(QWidget *parent)
    {
        m_iBorderWidth = 0;
        m_waterColor.setRgb(43, 123, 234);
        m_backgroundColor.setRgb(255, 255, 255);
        m_borderColor.setRgb(120, 120, 120);
        m_textColor.setRgb(0, 0, 0);
        m_dOffset = 0;
        //利用定时器固定时间内刷新页面,使得水浪动起来
        m_timer = new QTimer(this);
        m_timer->setSingleShot(false);
        connect(m_timer, &QTimer::timeout, this, [=](){
            if (this->isVisible())
            {
                //偏移量控制,每次绘制自加0.3,当超过一个正弦余弦2π周期时,就回退为0,加上定时器每50ms绘制一下,就触发了曲线的动态效果
                m_dOffset += 0.3;
                if (m_dOffset > 2 * M_PI)
                {
                    m_dOffset = 0;
                }
                this->update();
            }
        });
        m_timer->start(50);
    }
    
    WaterProgressBar::~WaterProgressBar()
    {
    }
    
    void WaterProgressBar::paintEvent(QPaintEvent *event)
    {
        //进度条不可见的情况下就不重绘了
        if (!this->isVisible())
        {
            return;
        }
        m_iValue = this->value() < 0 ? 0 : this->value();//初始化时QT进度条的进度为-1,避免负进度的出现
    
        QPainter painter(this);
        painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);//开启图和字体抗锯齿
    
        drawBackGround(&painter);//绘制背景
        drawWaterWave(&painter);//绘制水波
        drawText(&painter);//绘制进度文本
    }
    
    void WaterProgressBar::drawBackGround(QPainter* painter)
    {
        int width = this->width();
        int height = this->height();
        if (m_iBorderWidth > 0)
        {
            //根据窗口的长宽最小值得到外部背景直径
            int max_diameter = qMin(width, height);
            painter->save();
            painter->setBrush(QBrush(m_borderColor));
            painter->setPen(Qt::NoPen);
            //绘制边框背景,然后用内部背景覆盖,即可得到边框
            painter->drawEllipse(0, 0, max_diameter, max_diameter);
            painter->restore();
        }
        painter->save();
        //根据窗口的长宽最小值减去边框厚度得到内部背景直径
        int min_diameter = qMin(width, height) - (2 * m_iBorderWidth);
        painter->setBrush(QBrush(m_backgroundColor));
        painter->setPen(Qt::NoPen);
        painter->drawEllipse(m_iBorderWidth, m_iBorderWidth, min_diameter, min_diameter);
        painter->restore();
    }
    
    void WaterProgressBar::drawWaterWave(QPainter* painter)
    {
        int width = this->width();
        int height = this->height();
        //根据窗口的长宽最小值减去边框厚度得到直径
        int diameter = qMin(width, height) - (2 * m_iBorderWidth);
    
        //sincos曲线的波峰,波峰越大,水浪越高
        double waveHeight = 0.04*diameter;
        //sincos曲线的周期,周期越大,水浪越密
        double cycle = 2 * M_PI / diameter;
        //水的高度,可以理解为进度,注意由于我们的电脑坐标系是以左上角为原点,这和我们高中坐标系理解的不同
        double percent = (double)m_iValue / 100;
        double waterHeight = (1 - percent)*diameter + m_iBorderWidth;
    
        painter->save();
        QPainterPath totalPath;
        //加入圆形路径
        totalPath.addEllipse(m_iBorderWidth, m_iBorderWidth, diameter, diameter);
    
        //水波路径,先画浅色,再画深色
        QPainterPath water1;
        QPainterPath water2;
    
        water1.moveTo(m_iBorderWidth, m_iBorderWidth + diameter);
        water2.moveTo(m_iBorderWidth, m_iBorderWidth + diameter);
    
        //从左边起始点到右边结束点绘制两条波浪曲线
        for (int i = m_iBorderWidth; i <= m_iBorderWidth + diameter; i++)
        {
            double waterY1 = 0;
            double waterY2 = 0;
    
            if (m_iValue == 0 || m_iValue == 100)
            {
                waterY1 = waterY2 = waterHeight;
            }
            else
            {
                //第一条波浪Y轴
                waterY1 = (double)(waveHeight * qSin(cycle * (i - m_iBorderWidth) - M_PI / 2 + m_dOffset)) + waterHeight;//当正弦曲线前进π/2,sin的波峰和cos的波谷就对上了
                //第二条波浪Y轴
                waterY2 = (double)(waveHeight * qCos(cycle * (i - m_iBorderWidth) + m_dOffset)) + waterHeight;
            }
            water1.lineTo(i, waterY1);
            water2.lineTo(i, waterY2);
    
        }
    
        //封闭
        water1.lineTo(m_iBorderWidth + diameter, m_iBorderWidth + diameter);
        water2.lineTo(m_iBorderWidth + diameter, m_iBorderWidth + diameter);
    
        QPainterPath path;
        QColor waterColor1 = m_waterColor;
        waterColor1.setAlpha(100);
        QColor waterColor2 = m_waterColor;
        waterColor2.setAlpha(200);
    
        //第一条波浪
        path = totalPath.intersected(water1);
        painter->setBrush(waterColor1);
        painter->setPen(Qt::NoPen);
        painter->drawPath(path);
        painter->restore();
        painter->save();
    
        //第二条波浪挖去后的路径
        path = totalPath.intersected(water2);
        painter->setBrush(waterColor2);
        painter->setPen(Qt::NoPen);
        painter->drawPath(path);
    
        painter->restore();
    }
    
    void WaterProgressBar::drawText(QPainter* painter)
    {
        painter->save();
        int width = this->width();
        int height = this->height();
        //根据窗口的长宽最小值减去边框厚度得到直径
        int diameter = qMin(width, height) - (2 * m_iBorderWidth);
        int fontSize = diameter / 5;
        //设置文本字体
        QFont font;
        font.setFamily("微软雅黑");
        font.setPixelSize(fontSize);
        font.setBold(true);
        //绘制文本
        painter->setFont(font);
        painter->setPen(m_textColor);
        painter->drawText(QRectF(m_iBorderWidth, m_iBorderWidth, diameter, diameter), Qt::AlignCenter, QString("%1%").arg(m_iValue));
        painter->restore();
    }
  • 相关阅读:
    luogu_1339 [USACO09OCT]热浪Heat Wave
    luogu_1341 无序字母对
    luogu_1330 封锁阳光大学
    luogu_3383 【模板】线性筛素数
    luogu_1095 守望者的逃离
    luogu_1373 小a和uim之大逃离
    查看寄存器
    Assembly oth
    非常详细的端口表汇总
    公式证明
  • 原文地址:https://www.cnblogs.com/suxia/p/14308645.html
Copyright © 2011-2022 走看看