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:
-
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(); }