查看完整版本: [-- Qt编写动态圆形进度条 --]

QTCN开发网 -> Qt 作品展 -> Qt编写动态圆形进度条 [打印本页] 登录 -> 注册 -> 回复主题 -> 发表主题

liudianwu 2016-10-14 13:42

Qt编写动态圆形进度条

最近在整理用户自定义控件,包含开源的和修正的及自己写的。
参照Qt自己的命名,统一定义了一些书写规范:

1:所有命名均为首字母小写,例如setValue;
2:私有变量及函数不建议使用下划线;
3:设置用set开头,获取值用get开头;
4:公共方法和公有槽都要注释,私有的变量和方法建议注释。
5:方法及变量类似的含义的,可以靠在一起分组,不同分组间空一行。
6:所有公共方法,函数体超过一行的在头文件中只声明,实现文件中写具体方法。
7:void类型的公共方法全部改为公共槽。

头文件依次排列顺序:
public:构造函数及析构函数
protected:重写的方法,例如paintEvent等。
private:私有变量
private slots:私有槽函数
public:公共方法
public slots:公有槽函数
signal:信号

  1. #ifndef ROUNDPLOT_H
    #define ROUNDPLOT_H

    #include <QWidget>

    /**
    * 作者:feiyangqingyun(QQ:517216493) 2016-10-14
    * 本控件来源于网络(原作者:不详),本人重写90%的代码
    */

    class RoundPlot : public QWidget
    {
        Q_OBJECT
    public:
        RoundPlot(QWidget *parent = 0);
        ~RoundPlot();

    protected:
        void paintEvent(QPaintEvent *event);

    private:
        int minValue;               //最小值
        int maxValue;               //最大值
        int value;                  //目标值
        QString unit;               //单位

        int currentValue;           //当前值
        int step;                   //步长,动态变化时每次增加的步长

        QColor usedColor;           //已使用百分比颜色
        QColor freeColor;           //未使用百分比颜色

        QColor rangeTextColor;      //范围值文字颜色
        QColor valueTextColor;      //目标值文字颜色

        QColor valueBgColor;        //目标值背景色
        QColor outBgColor;          //外边框背景色
        QColor centerBgColorStart;  //中间圆环渐变背景起始颜色
        QColor centerBgColorEnd;    //中间圆环渐变背景结束颜色

        QFont rangeTextFont;        //范围值文字字体
        QFont valueTextFont;        //目标值文字字体

        QTimer *updateTimer;        //绘制定时器

    private slots:
        void updateValue();

    public:
        //获取最小值
        int getMinValue()const
        {
            return minValue;
        }

        //获取最大值
        int getMaxValue()const
        {
            return maxValue;
        }

        //获取目标值
        int getValue()const
        {
            return value;
        }

        //获取单位
        QString getUnit()const
        {
            return unit;
        }

    public slots:
        //设置最大最小值-范围值
        void setRange(int minValue, int maxValue);
        //设置目标值
        void setValue(int value);
        //设置文字后面的单位
        void setUnit(QString unit);

        //设置已使用百分比颜色
        void setUsedColor(QColor usedColor);
        //设置未使用百分比颜色
        void setFreeColor(QColor freeColor);

        //设置范围值文字颜色
        void setRangeTextColor(QColor rangeTextColor);
        //设置目标值文字颜色
        void setValueTextColor(QColor valueTextColor);

        //设置目标值背景色
        void setValueBgColor(QColor valueBgColor);
        //设置外边框背景色
        void setOutBgColor(QColor outBgColor);
        //设置中央圆形背景色
        void setCenterBgColor(QColor centerBgColorStart, QColor centerBgColorEnd);

        //设置范围值文字字体
        void setRangeTextFont(QFont rangeTextFont);
        //设置目标值文字字体
        void setValueTextFont(QFont valueTextFont);    
    };

    #endif // ROUNDPLOT_H

  1. #include "roundplot.h"
    #include "qtimer.h"
    #include "qpainter.h"
    #include "qapplication.h"
    #include "qevent.h"
    #include "qdesktopwidget.h"
    #include "qdebug.h"

    RoundPlot::RoundPlot(QWidget *parent)
        : QWidget(parent, Qt::FramelessWindowHint)
    {
        setMinimumSize(167, 167);
        setAutoFillBackground(true);
        QPalette palette = this->palette();
        palette.setColor(QPalette::Background, QColor(255, 255, 255));
        setPalette(palette);

        minValue = 0;
        maxValue = 100;
        value = 0;
        unit = "";

        currentValue = 0;
        step = maxValue / 100;    

        usedColor = QColor(165, 220, 62);
        freeColor = QColor(215, 215, 215);

        rangeTextColor = QColor(137, 137, 137);
        valueTextColor = QColor(52, 155, 218);

        valueBgColor = QColor(239, 239, 239);
        outBgColor = QColor(233, 233, 233);
        centerBgColorStart = QColor(45, 204, 112);
        centerBgColorEnd = QColor(51, 152, 219);

        rangeTextFont = QFont("Arial", 10, QFont::Normal);
        valueTextFont = QFont("Arial", 15, QFont::Bold);    

        updateTimer = new QTimer(this);
        updateTimer->setInterval(10);
        connect(updateTimer, SIGNAL(timeout()), this, SLOT(updateValue()));
    }

    RoundPlot::~RoundPlot()
    {
        if (updateTimer->isActive()) {
            updateTimer->stop();
        }
    }

    void RoundPlot::paintEvent(QPaintEvent *event)
    {
        Q_UNUSED(event)
        int width = this->width();
        int height = this->height();

        //直径取宽高中最短的一个
        int diameter = width > height ? height : width;

        //绘制准备工作,旋转坐标轴中心
        QPainter painter(this);
        painter.setRenderHint(QPainter::Antialiasing);
        painter.setRenderHint(QPainter::SmoothPixmapTransform);
        painter.translate(width / 2, height / 2);
        painter.save();
        painter.rotate(40);

        //自动计算比例关系
        double percent = (double)100 / (maxValue - minValue);
        int currentPercent = currentValue * percent;
        int maxPercent = maxValue * percent;

        //自动计算位置比例
        double diameterLine = ((double)3 / 167) * diameter;
        double diameterWidth = ((double)70 / 167) * diameter;
        double diameterHeight = ((double)80 / 167) * diameter;
        double diameter1 = ((double)55 / 167) * diameter;
        double diameter2 = ((double)35 / 167) * diameter;
        double diameter3 = ((double)30 / 167) * diameter;
        double diameter4 = ((double)80 / 167) * diameter;
        double diameter5 = ((double)135 / 167) * diameter;

        //绘制当前百分比
        painter.setPen(QPen(usedColor, diameterLine));

        for (int i = minValue; i < currentPercent; i++) {
            painter.drawLine(0, diameterWidth, 0, diameterHeight);
            painter.rotate(2.8);
        }

        //绘制空余百分比
        painter.setPen(QPen(freeColor, diameterLine));

        for (int i = currentPercent; i < maxPercent; i++) {
            painter.drawLine(0, diameterWidth, 0, diameterHeight);
            painter.rotate(2.8);
        }

        painter.restore();

        //绘制最外框圆形背景
        painter.translate(-width / 2, -height / 2);
        painter.setBrush(outBgColor);
        painter.setPen(QPen(outBgColor, 15));
        painter.drawEllipse(QRectF((width / 2 - diameter1), (height / 2 - diameter1), diameter1 * 2, diameter1 * 2));

        //绘制中间框圆形渐变背景
        QConicalGradient conicalGradient(width / 2, height / 2, 90);
        conicalGradient.setColorAt(0, centerBgColorStart);
        conicalGradient.setColorAt(1.0, centerBgColorEnd);
        painter.setPen(QPen(QBrush(conicalGradient), 30));
        painter.drawEllipse(QRectF((width / 2 - diameter2), (height / 2 - diameter2), diameter2 * 2, diameter2 * 2));

        //绘制最里框百分比文字圆形背景
        painter.setPen(Qt::NoPen);
        painter.setBrush(valueBgColor);
        painter.drawEllipse(QRectF((width / 2 - diameter3), (height / 2 - diameter3), diameter3 * 2, diameter3 * 2));

        //绘制百分比文字及范围值文字
        painter.setPen(QPen(valueTextColor));
        painter.setFont(valueTextFont);
        painter.drawText(0, 0, width, height, Qt::AlignCenter, tr("%1%2").arg(currentValue).arg(unit));
        painter.setPen(QPen(rangeTextColor));
        painter.setFont(rangeTextFont);
        painter.drawText(0, 0, width - diameter4, height + diameter5, Qt::AlignCenter, tr("%1%2").arg(minValue).arg(unit));
        painter.drawText(0, 0, width + diameter4, height + diameter5, Qt::AlignCenter, tr("%1%2").arg(maxValue).arg(unit));
    }

    void RoundPlot::updateValue()
    {
        if (currentValue >= value) {
            updateTimer->stop();
            return;
        }

        currentValue = currentValue + step;
        update();
    }

    void RoundPlot::setRange(int minValue, int maxValue)
    {
        if (updateTimer->isActive()) {
            updateTimer->stop();
        }

        currentValue = minValue;
        this->minValue = minValue;
        this->maxValue = maxValue;

        //如果目标值不在范围值内,则重新设置目标值
        if (value < minValue || value > maxValue) {
            setValue(value);
        }

        //自动计算步长,步长=最大值/100
        step = maxValue / 100;
    }

    void RoundPlot::setValue(int value)
    {
        //如果目标值比最小值小则取最小值,如果目标值比最大值大则取最大值
        if (value < minValue) {
            this->value = minValue;
        } else if (value > maxValue) {
            this->value = maxValue;
        } else {
            this->value = value;
        }

        updateTimer->start();
    }

    void RoundPlot::setUnit(QString unit)
    {
        this->unit = unit;
        update();
    }

    void RoundPlot::setUsedColor(QColor usedColor)
    {
        this->usedColor = usedColor;
        update();
    }

    void RoundPlot::setFreeColor(QColor freeColor)
    {
        this->freeColor = freeColor;
        update();
    }

    void RoundPlot::setRangeTextColor(QColor rangeTextColor)
    {
        this->rangeTextColor = rangeTextColor;
        update();
    }

    void RoundPlot::setValueTextColor(QColor valueTextColor)
    {
        this->valueTextColor = valueTextColor;
        update();
    }

    void RoundPlot::setValueBgColor(QColor valueBgColor)
    {
        this->valueBgColor = valueBgColor;
        update();
    }

    void RoundPlot::setOutBgColor(QColor outBgColor)
    {
        this->outBgColor = outBgColor;
        update();
    }

    void RoundPlot::setCenterBgColor(QColor centerBgColorStart, QColor centerBgColorEnd)
    {
        this->centerBgColorStart = centerBgColorStart;
        this->centerBgColorEnd = centerBgColorEnd;
        update();
    }

    void RoundPlot::setRangeTextFont(QFont rangeTextFont)
    {
        this->rangeTextFont = rangeTextFont;
        update();
    }

    void RoundPlot::setValueTextFont(QFont valueTextFont)
    {
        this->valueTextFont = valueTextFont;
        update();
    }

使用方法:
  1. #include "frmroundplot.h"
    #include "ui_frmroundplot.h"
    #include "myhelper.h"
    #include "control/roundplot.h"

    frmRoundPlot::frmRoundPlot(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::frmRoundPlot)
    {
        ui->setupUi(this);
        ui->widget2->setUsedColor(QColor(41, 137, 219));
        ui->widget2->setFreeColor(QColor(50, 50, 50));
        ui->widget2->setRangeTextColor(QColor(103, 103, 103));
        ui->widget2->setValueTextColor(QColor(250, 250, 250));
        ui->widget2->setValueBgColor(QColor(45, 169, 222));
        ui->widget2->setOutBgColor(QColor(202, 225, 255));
        ui->widget2->setCenterBgColor(QColor(67, 205, 128), QColor(60, 179, 113));
        ui->widget2->setRangeTextFont(QFont("Microsoft Yahei", 10, QFont::Normal));
        ui->widget2->setValueTextFont(QFont("Microsoft Yahei", 18, QFont::Normal));
        on_pushButton_clicked();
    }

    frmRoundPlot::~frmRoundPlot()
    {
        delete ui;
    }

    void frmRoundPlot::on_pushButton_clicked()
    {
        int min = ui->txtMin->text().toInt();
        int max = ui->txtMax->text().toInt();
        int current = ui->txtCurrent->text().toInt();
        QString unit = ui->txtUnit->text();

        ui->widget1->setRange(min, max);
        ui->widget2->setRange(min, max);
        ui->widget1->setValue(current);
        ui->widget2->setValue(current);
        ui->widget1->setUnit(unit);
        ui->widget2->setUnit(unit);
    }
效果
[attachment=15885]

仗剑天涯 2016-10-14 14:08
大神新品,赞一个

书生也疯狂 2016-10-14 14:36
大神,膜拜学习!

listen342325 2016-10-14 14:50
最小大小167,这个可不可以改?

liudianwu 2016-10-14 17:04
listen342325:最小大小167,这个可不可以改? (2016-10-14 14:50) 

肯定可以改的。

crazy 2016-10-16 09:21
        

disongshu 2016-10-17 12:17
    

那就地方iv 2016-10-18 08:14
膜拜大神新作

哥依然潇洒 2016-10-24 11:21
大神,你真实我在Qt上的指路人啊

mu_de_yu 2017-01-17 13:33
    

mu_de_yu 2017-01-17 13:33
    

panfan 2017-01-18 10:49
            

tedboston 2017-01-18 19:55
怎么没有这个Qroundplot类啊

zwk0704 2017-04-11 22:27

先赞再看

zwk0704 2017-04-12 00:29
反馈:
1.采用定时器绘制,如果数值过大,不处理直接输入,耗时,对程序其他运行程序不好
2.不能小数显示,当然楼主也说了是进度,不过也应该考虑小数
P.S
上述问题在楼组下一篇博文得到了解决,赞

iehttp 2017-05-08 10:13
神赞一下

a798213343 2020-12-09 15:37
请问可以使用qml去实现吗


查看完整版本: [-- Qt编写动态圆形进度条 --] [-- top --]



Powered by phpwind v8.7 Code ©2003-2011 phpwind
Gzip disabled