Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

How to draw a smooth arc



  • I have three LineEdits in dialog window. When the user types something in them, an arc is drawn(the arc degree is based on the number of empty lineEdits).
    I have overrided and implemented QPaintEvent and set the slots to LineEdits textChanged signal, and my code worked fine. In order to draw a smooth arc, I have used QPropertyanimation(which exists in the following code) and got the warning: "you're trying to animate a non-existing property pen of your QObject". After searching about this warning, I found out that I should override and implement timerEvent() instead of using QPropertyanimation.
    I would appreciate if someone could help me implementing timerEvent or suggest another way in order to draw a smooth arc.

    Here is the code:

    dialog.h:

    #ifndef DIALOG_H
    #define DIALOG_H
    
    #include <QDialog>
    #include <QPainter>
    #include <QPen>
    #include <QRectF>
    #include <QSlider>
    #include <QLineEdit>
    #include <QPropertyAnimation>
    
    namespace Ui {
    class Dialog;
    }
    
    class Dialog : public QDialog
    {
        Q_OBJECT
    
    public:
        explicit Dialog(QWidget *parent = 0);
        ~Dialog();
        QPainter p;
        QPen pen;
        double progress;
        int startAngle;
        int spanAngle;
        QLineEdit *lineEdit_1;
        QLineEdit *lineEdit_2 ;
        QLineEdit *lineEdit_3;
        QPropertyAnimation *animation;
    
    
    
    public slots:
        void setProgress();
        void setProgress2();
        void setProgress3();
    
    
    protected:
        void paintEvent(QPaintEvent *);
        
    
    private:
        Ui::Dialog *ui;
    
    };
    
    #endif // DIALOG_H
    
    

    dialog.cpp:

    #include "dialog.h"
    #include "ui_dialog.h"
    #include <QConicalGradient>
    #include <QPropertyAnimation>
    
    Dialog::Dialog(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::Dialog)
    {
        ui->setupUi(this);
    
        lineEdit_1 = new QLineEdit(this);
        lineEdit_1->setGeometry(400,50,100,50);
        lineEdit_1->show();
    
    
        lineEdit_2 = new QLineEdit(this);
        lineEdit_2->setGeometry(400,150,100,50);
        lineEdit_2->show();
    
    
        lineEdit_3 = new QLineEdit(this);
        lineEdit_3->setGeometry(400,250,100,50);
        lineEdit_3->show();
    
         connect(lineEdit_1, SIGNAL(textChanged(const QString &)), this, SLOT(setProgress()));
         connect(lineEdit_2, SIGNAL(textChanged(const QString &)), this, SLOT(setProgress2()));
         connect(lineEdit_3, SIGNAL(textChanged(const QString &)), this, SLOT(setProgress3()));
    
    }
    
    Dialog::~Dialog()
    {
        delete ui;
    }
    
    void Dialog::setProgress()
    {
    
        if(lineEdit_1->text().isEmpty())
        {
            if(lineEdit_2->text().isEmpty() && lineEdit_3->text().isEmpty())
            {
                progress = 0;
                this->update();
            }
            else if(lineEdit_2->text().isEmpty() || lineEdit_3->text().isEmpty())
            {
                progress = 120;
                this->update();
            }
            else
            {
                progress = 240;
                this->update();
            }
    
        }
        else
        {
            if(lineEdit_2->text().isEmpty() && lineEdit_3->text().isEmpty())
            {
                progress = 120;
                this->update();
            }
            else if(lineEdit_2->text().isEmpty() || lineEdit_3->text().isEmpty())
            {
                progress = 240;
                this->update();
            }
            else
            {
                progress = 360;
                this->update();
            }
    
        }
    
    
    
    }
    
    void Dialog::setProgress2()
    {
    
        if(lineEdit_2->text().isEmpty())
        {
            if(lineEdit_1->text().isEmpty() && lineEdit_3->text().isEmpty())
            {
                progress = 0;
                this->update();
            }
            else if(lineEdit_1->text().isEmpty() || lineEdit_3->text().isEmpty())
            {
                progress = 120;
                this->update();
            }
            else
            {
                progress = 240;
                this->update();
            }
    
        }
        else
        {
            if(lineEdit_1->text().isEmpty() && lineEdit_3->text().isEmpty())
            {
                progress = 120;
                this->update();
            }
            else if(lineEdit_1->text().isEmpty() || lineEdit_3->text().isEmpty())
            {
                progress = 240;
                this->update();
            }
            else
            {
                progress = 360;
                this->update();
            }
    
        }
    
    
    }
    
    
    void Dialog::setProgress3()
    {
        if(lineEdit_3->text().isEmpty())
        {
    
            if(lineEdit_1->text().isEmpty() && lineEdit_2->text().isEmpty())
            {
                progress = 0;
                this->update();
            }
            else if(lineEdit_1->text().isEmpty() || lineEdit_2->text().isEmpty())
            {
                progress = 120;
                this->update();
            }
            else
            {
                progress = 240;
                this->update();
            }
        }
        else
        {
    
    
            if(lineEdit_1->text().isEmpty() && lineEdit_2->text().isEmpty())
            {
                progress = 120;
                this->update();
            }
            else if(lineEdit_1->text().isEmpty() || lineEdit_2->text().isEmpty())
            {
                progress = 240;
                this->update();
            }
            else
            {
                progress = 360;
                this->update();
            }
    
    
        }
    
    }
    
    
    
    
    void Dialog::paintEvent(QPaintEvent *)
    {
        QPainter p(this);
    
        QRectF rectangle(100.0, 70.0, 100.0, 100.0);
    
        QConicalGradient gradient;
        gradient.setCenter(rectangle.center());
        gradient.setAngle(30);
        gradient.setColorAt(0, QColor(178, 255, 246));
        gradient.setColorAt(1, QColor(5, 44, 50));
    
    
        QPen pen(QBrush(gradient), 10);
        p.setPen(pen);
        p.setRenderHint(QPainter::Antialiasing);
    
       int startAngle = 0 * 16;
       int spanAngle = progress * 16;
       p.drawArc(rectangle, startAngle, spanAngle);
    
    
       //.............make the arc smooth.............//
       animation = new QPropertyAnimation(this,"pen");
       animation->setDuration(1000);
       animation->setStartValue(QRect(460,30,853,114));
       animation->setEndValue(QRect(460,30,853,824));
       animation->start();
    
    
    
    
        //.........numbers in the center......//
        QPainter p2(this);
        QPen pen2;
        pen2.setWidth(7);
        pen2.setColor(Qt::black);
        p2.setPen(pen2);
    
    
        if(progress==120)
        {
            p2.drawText(rectangle,Qt::AlignCenter,QString::number(33.3)+" %");
        }
        else if(progress==240)
        {
            p2.drawText(rectangle,Qt::AlignCenter,QString::number(66.6)+" %");
        }
        else if(progress==360)
        {
            p2.drawText(rectangle,Qt::AlignCenter,QString::number(100)+" %");
        }
        else
        {
            p2.drawText(rectangle,Qt::AlignCenter,QString::number(0)+" %");
        }
    
    }
    
    
    

    main.cpp:

    #include "dialog.h"
    #include <QApplication>
    #include <QSlider>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        Dialog w;
        w.show();
    
    
        return a.exec();
    }
    
    

    The output:

    output.png



  • I found the solution!
    I set SmoothArc slot to these three lineEdits and then I used QVarientAnimation inside this slot. Then using the onValueChanged(QVariant) slot which is specific for QVarientAnimation class, I changed the degree of arc which is changing from 0 to the progress value.
    Here is the following code:

    dialog.h:

    #ifndef DIALOG_H
    #define DIALOG_H
    
    #include <QDialog>
    #include <QLineEdit>
    #include <QVariantAnimation>
    #include <QPainter>
    
    namespace Ui {
    class Dialog;
    }
    
    class Dialog : public QDialog
    {
     Q_OBJECT
    
    public:
     explicit Dialog(QWidget *parent = 0);
     ~Dialog();
    
     QLineEdit *lineEdit_1;
     QLineEdit *lineEdit_2;
     QLineEdit *lineEdit_3;
     QVariantAnimation *animation;
     int progress;
    
    
    public slots:
     void setProgress();
     void setProgress2();
     void setProgress3();
     void SmoothArc();
     void onValueChanged(const QVariant &value);
    
    
    
    private:
     Ui::Dialog *ui;
     int mvalue = 0;
    
    
    protected:
      void paintEvent(QPaintEvent *);
    };
    
    #endif // DIALOG_H
    
    

    dialog.cpp:

    #include "dialog.h"
    #include "ui_dialog.h"
    
    Dialog::Dialog(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::Dialog)
    
    {
        ui->setupUi(this);
    
        lineEdit_1 = new QLineEdit(this);
        lineEdit_1->setGeometry(400,50,100,50);
        lineEdit_1->show();
    
        lineEdit_2 = new QLineEdit(this);
        lineEdit_2->setGeometry(400,150,100,50);
        lineEdit_2->show();
    
    
        lineEdit_3 = new QLineEdit(this);
        lineEdit_3->setGeometry(400,250,100,50);
        lineEdit_3->show();
    
    
    
        connect(lineEdit_1, SIGNAL(textChanged(const QString &)), this, SLOT(setProgress()));
        connect(lineEdit_1, SIGNAL(textChanged(const QString &)), this, SLOT(SmoothArc()));
    
        connect(lineEdit_2, SIGNAL(textChanged(const QString &)), this, SLOT(setProgress2()));
        connect(lineEdit_2, SIGNAL(textChanged(const QString &)), this, SLOT(SmoothArc()));
    
    
        connect(lineEdit_3, SIGNAL(textChanged(const QString &)), this, SLOT(setProgress3()));
        connect(lineEdit_3, SIGNAL(textChanged(const QString &)), this, SLOT(SmoothArc()));
    
    }
    
    Dialog::~Dialog()
    {
        delete ui;
    }
    
    void Dialog::setProgress()
    {
    
        if(lineEdit_1->text().isEmpty())
        {
            if(lineEdit_2->text().isEmpty() && lineEdit_3->text().isEmpty())
            {
                progress = 0;
                this->update();
            }
            else if(lineEdit_2->text().isEmpty() || lineEdit_3->text().isEmpty())
            {
                progress = 120;
                this->update();
            }
            else
            {
                progress = 240;
                this->update();
            }
    
        }
        else
        {
            if(lineEdit_2->text().isEmpty() && lineEdit_3->text().isEmpty())
            {
                progress = 120;
                this->update();
            }
            else if(lineEdit_2->text().isEmpty() || lineEdit_3->text().isEmpty())
            {
                progress = 240;
                this->update();
            }
            else
            {
                progress = 360;
                this->update();
            }
    
        }
    
    
    
    }
    
    
    void Dialog::setProgress2()
    {
    
        if(lineEdit_2->text().isEmpty())
        {
            if(lineEdit_1->text().isEmpty() && lineEdit_3->text().isEmpty())
            {
                progress = 0;
                this->update();
            }
            else if(lineEdit_1->text().isEmpty() || lineEdit_3->text().isEmpty())
            {
                progress = 120;
                this->update();
            }
            else
            {
                progress = 240;
                this->update();
            }
    
        }
        else
        {
            if(lineEdit_1->text().isEmpty() && lineEdit_3->text().isEmpty())
            {
                progress = 120;
                this->update();
            }
            else if(lineEdit_1->text().isEmpty() || lineEdit_3->text().isEmpty())
            {
                progress = 240;
                this->update();
            }
            else
            {
                progress = 360;
                this->update();
            }
    
        }
    
    
    }
    
    void Dialog::setProgress3()
    {
        if(lineEdit_3->text().isEmpty())
        {
    
            if(lineEdit_1->text().isEmpty() && lineEdit_2->text().isEmpty())
            {
                progress = 0;
                this->update();
            }
            else if(lineEdit_1->text().isEmpty() || lineEdit_2->text().isEmpty())
            {
                progress = 120;
                this->update();
            }
            else
            {
                progress = 240;
                this->update();
            }
        }
        else
        {
    
    
            if(lineEdit_1->text().isEmpty() && lineEdit_2->text().isEmpty())
            {
                progress = 120;
                this->update();
            }
            else if(lineEdit_1->text().isEmpty() || lineEdit_2->text().isEmpty())
            {
                progress = 240;
                this->update();
            }
            else
            {
                progress = 360;
                this->update();
            }
    
    
        }
    
    }
    
    
    void Dialog::paintEvent(QPaintEvent *)
    {
        QPainter p(this);
    
        QRectF rectangle(100.0, 70.0, 100.0, 100.0);
    
        QConicalGradient gradient;
        gradient.setCenter(rectangle.center());
        gradient.setAngle(30);
        gradient.setColorAt(0, QColor(178, 255, 246));
        gradient.setColorAt(1, QColor(5, 44, 50));
    
    
        QPen pen(QBrush(gradient), 10);
        p.setPen(pen);
        p.setRenderHint(QPainter::Antialiasing);
    
       int startAngle = 0;
       int spanAngle = mvalue * 16;
    
       p.drawArc(rectangle, startAngle, spanAngle);
    
    
    }
    
    //.......................draw smooth arc.....................//
    void Dialog::SmoothArc()
    {
    
         animation = new QVariantAnimation(this);
         animation->setStartValue(mvalue);
         animation->setEndValue(progress);
         animation->setDuration(1500);
         animation->start();
    
         connect(animation, SIGNAL(valueChanged(QVariant)), this, SLOT(onValueChanged(QVariant)));
    
    }
    
    void Dialog::onValueChanged(const QVariant &value)
    {
        mvalue = value.toDouble();
        update();
    
    }
    
    

    main.cpp:

    #include "dialog.h"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        Dialog w;
        w.show();
    
        return a.exec();
    }
    
    

Log in to reply