Qt Writing Custom Control 12-Progress Dashboard

Preface

The main application scenario of the progress dashboard is to identify the status of a task's progress and so on. It can set range values and current values freely. Four kinds of indicators (circular indicator/pointer indicator/rounded pointer indicator/triangle indicator) are also provided for beauty. All kinds of colors can be set. The animation effect can be achieved by using QProperty Animation class, which is mainly composed of four indicators (circular indicator/pointer indicator/rounded pointer indicator/triang Linear interpolation method generates a number of rules for setting attributes. Today, a friend needs android version of the control, in fact, the control written by qwidget can be directly compiled to android, so directly recompiled the android version, the corresponding apk has been uploaded to the shared folder, and at the end of the article posted the android running effect map.

Functions realized

  • 1: Supporting Indicator Style Selection Circular Indicator/Pointer Indicator/Corner Indicator/Triangle Indicator
  • 2: Support the mouse to press and rotate to change the value
  • 3: Support negative range values
  • 4: Support setting current and range values
  • 5: Support setting start and end rotation angles
  • 6: Support setting background color/progress color/middle circle gradient color
  • 7: Automatically change with form stretching
  • 8: Support mouse entry and exit animation effects
  • 9: Set whether to display the current value
  • 10: Indicators can be set

Design sketch

Header file code

#ifndef GAUGEPROGRESS_H
#define GAUGEPROGRESS_H

/**
 * Progress bar dashboard control author: feiyangqingyun(QQ:517216493) 2016-12-03
 * 1:Support Indicator Style Selection Round Indicator/Pointer Indicator/Corner Indicator/Triangle Indicator
 * 2:Support Mouse Press Rotation Change Value
 * 3:Support negative range values
 * 4:Support setting current and range values
 * 5:Support setting start and end rotation angles
 * 6:Support setting background color/progress color/mid-circle gradient color
 * 7:Automatic change with form stretching
 * 8:Support mouse entry and exit animation effects
 * 9:Can set whether to display the current value
 * 10:Can set whether to display indicator or not
 */

#include <QWidget>
#include <QVariant>

class QPropertyAnimation;

#ifdef quc
#if (QT_VERSION < QT_VERSION_CHECK(5,7,0))
#include <QtDesigner/QDesignerExportWidget>
#else
#include <QtUiPlugin/QDesignerExportWidget>
#endif

class QDESIGNER_WIDGET_EXPORT GaugeProgress : public QWidget
#else
class GaugeProgress : public QWidget
#endif

{
	Q_OBJECT
	Q_ENUMS(PointerStyle)

	Q_PROPERTY(double minValue READ getMinValue WRITE setMinValue)
	Q_PROPERTY(double maxValue READ getMaxValue WRITE setMaxValue)
    Q_PROPERTY(double value READ getValue WRITE setValue)
	Q_PROPERTY(int precision READ getPrecision WRITE setPrecision)

	Q_PROPERTY(int startAngle READ getStartAngle WRITE setStartAngle)
	Q_PROPERTY(int endAngle READ getEndAngle WRITE setEndAngle)

	Q_PROPERTY(QColor bgColor READ getBgColor WRITE setBgColor)
	Q_PROPERTY(QColor progressColor READ getProgressColor WRITE setProgressColor)
	Q_PROPERTY(QColor progressBgColor READ getProgressBgColor WRITE setProgressBgColor)
	Q_PROPERTY(QColor circleColorStart READ getCircleColorStart WRITE setCircleColorStart)
	Q_PROPERTY(QColor circleColorEnd READ getCircleColorEnd WRITE setCircleColorEnd)
	Q_PROPERTY(QColor textColor READ getTextColor WRITE setTextColor)

	Q_PROPERTY(bool showPointer READ getShowPointer WRITE setShowPointer)
	Q_PROPERTY(bool showValue READ getShowValue WRITE setShowValue)
	Q_PROPERTY(PointerStyle pointerStyle READ getPointerStyle WRITE setPointerStyle)

public:
	enum PointerStyle {
		PointerStyle_Circle = 0,        //Circular indicator
		PointerStyle_Indicator = 1,     //Pointer indicator
		PointerStyle_IndicatorR = 2,    //Rounded pointer indicator
		PointerStyle_Triangle = 3       //Triangle indicator
	};

    explicit GaugeProgress(QWidget *parent = 0);
    ~GaugeProgress();

protected:
	void enterEvent(QEvent *);
	void leaveEvent(QEvent *);
	void mousePressEvent(QMouseEvent *);
	void mouseReleaseEvent(QMouseEvent *);
	void mouseMoveEvent(QMouseEvent *);
	void paintEvent(QPaintEvent *);
	void drawBg(QPainter *painter);
	void drawColorPie(QPainter *painter);
	void drawCoverCircle(QPainter *painter);
	void drawCircle(QPainter *painter);
	void drawPointerCircle(QPainter *painter);
	void drawPointerIndicator(QPainter *painter);
	void drawPointerIndicatorR(QPainter *painter);
	void drawPointerTriangle(QPainter *painter);
    void drawValue(QPainter *painter);

private:	
    double minValue;                //minimum value
    double maxValue;                //Maximum value
    double value;                   //target value
	int precision;                  //Accuracy, after decimal points

	int startAngle;                 //Start rotation angle
	int endAngle;                   //End rotation angle

	QColor bgColor;                 //background color
	QColor progressColor;           //Current progress color
	QColor progressBgColor;         //Progress Background Color
	QColor circleColorStart;        //Middle circle gradient start color
	QColor circleColorEnd;          //Mid-circle Gradient End Color
	QColor textColor;               //Text color

	bool showPointer;               //Whether to display indicator
	bool showValue;                 //Whether to display the current value
	PointerStyle pointerStyle;      //Pointer style

	bool hover;                     //Whether to hover the mouse or not
	int radiusCoverCircle;          //Covering circle radius
	int radiusCircle;               //Radius of middle circle
	QPropertyAnimation *animation;  //Animated objects

private slots:
	void setEasingCurve();
	void updateRadius(QVariant radius);

private:
	//Whether or not to press the mouse
	bool pressed;
	//Set the current coordinate value according to the coordinates pressed by the mouse
	void setPressedValue(QPointF pressedPoint);

public:	
	double getMinValue()            const;
	double getMaxValue()            const;
    double getValue()               const;
	int getPrecision()              const;

	int getStartAngle()             const;
	int getEndAngle()               const;

	QColor getBgColor()             const;
	QColor getProgressColor()       const;
	QColor getProgressBgColor()     const;
	QColor getCircleColorStart()    const;
	QColor getCircleColorEnd()      const;
	QColor getTextColor()           const;

	bool getShowPointer()           const;
	bool getShowValue()             const;
	PointerStyle getPointerStyle()  const;

	QSize sizeHint()                const;
	QSize minimumSizeHint()         const;

public Q_SLOTS:
	//Set range values
	void setRange(double minValue, double maxValue);
	void setRange(int minValue, int maxValue);

	//Set maximum and minimum
	void setMinValue(double minValue);
	void setMaxValue(double maxValue);

	//Setting target values
	void setValue(double value);
	void setValue(int value);

	//Setting Accuracy
	void setPrecision(int precision);

	//Set the start rotation angle
	void setStartAngle(int startAngle);
	//Set the end rotation angle
	void setEndAngle(int endAngle);

	//Setting Background Colors
    void setBgColor(const QColor &bgColor);

	//Setting progress color
    void setProgressColor(const QColor &progressColor);
    void setProgressBgColor(const QColor &progressBgColor);

	//Set the color of the middle circle
    void setCircleColorStart(const QColor &circleColorStart);
    void setCircleColorEnd(const QColor &circleColorEnd);

	//Setting Text Colors
    void setTextColor(const QColor &textColor);

	//Set whether the indicator is displayed
	void setShowPointer(bool showPointer);
	//Set whether the current value is displayed
	void setShowValue(bool showValue);
	//Setting pointer style
    void setPointerStyle(const PointerStyle &pointerStyle);

Q_SIGNALS:
	void valueChanged(int value);
};

#endif // GAUGEPROGRESS_H


Core code

void GaugeProgress::paintEvent(QPaintEvent *)
{
    int width = this->width();
    int height = this->height();
    int side = qMin(width, height);

    //Drawing preparation, enabling anti-aliasing, translating coordinate axis center, scaling in equal proportion
    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
    painter.translate(width / 2, height / 2);
    painter.scale(side / 200.0, side / 200.0);

    //Drawing background
    drawBg(&painter);
    //Pie circle
    drawColorPie(&painter);
    //Draw a covering circle to cover the redundant parts of the pie circle.
    drawCoverCircle(&painter);
    //Drawing the central circle
    drawCircle(&painter);

    //Draw the indicator according to the shape of the indicator
    if (pointerStyle == PointerStyle_Circle) {
        drawPointerCircle(&painter);
    } else if (pointerStyle == PointerStyle_Indicator) {
        drawPointerIndicator(&painter);
    } else if (pointerStyle == PointerStyle_IndicatorR) {
        drawPointerIndicatorR(&painter);
    } else if (pointerStyle == PointerStyle_Triangle) {
        drawPointerTriangle(&painter);
    }

    //Draw the current value
    drawValue(&painter);
}

void GaugeProgress::drawBg(QPainter *painter)
{
    int radius = 99;
    painter->save();
    painter->setPen(Qt::NoPen);
    painter->setBrush(bgColor);
    painter->drawEllipse(-radius, -radius, radius * 2, radius * 2);
    painter->restore();
}

void GaugeProgress::drawColorPie(QPainter *painter)
{
    int radius = 95;
    painter->save();
    painter->setPen(Qt::NoPen);

    QRectF rect(-radius, -radius, radius * 2, radius * 2);

    //Calculate total range angle, current range angle, residual range angle
    double angleAll = 360.0 - startAngle - endAngle;
    double angleCurrent = angleAll * ((value - minValue) / (maxValue - minValue));
    double angleOther = angleAll - angleCurrent;

    //Draw the current value pie circle
    painter->setBrush(progressColor);
    painter->drawPie(rect, (270 - startAngle - angleCurrent) * 16, angleCurrent * 16);

    //Drawing Residual Value Pie Circle
    painter->setBrush(progressBgColor);
    painter->drawPie(rect, (270 - startAngle - angleCurrent - angleOther) * 16, angleOther * 16);

    painter->restore();
}

void GaugeProgress::drawCoverCircle(QPainter *painter)
{
    int radius = radiusCoverCircle;
    painter->save();
    painter->setPen(Qt::NoPen);
    painter->setBrush(bgColor);
    painter->drawEllipse(-radius, -radius, radius * 2, radius * 2);
    painter->restore();
}

void GaugeProgress::drawCircle(QPainter *painter)
{
    int radius = radiusCircle;
    painter->save();
    painter->setPen(Qt::NoPen);
    QLinearGradient bgGradient(0, -radius, 0, radius);
    bgGradient.setColorAt(0.0, circleColorStart);
    bgGradient.setColorAt(1.0, circleColorEnd);
    painter->setBrush(bgGradient);

    painter->drawEllipse(-radius, -radius, radius * 2, radius * 2);
    painter->restore();
}

void GaugeProgress::drawPointerCircle(QPainter *painter)
{
    if (!showPointer) {
        return;
    }

    int radius = 15;
    int offset = radiusCircle - 60;
    painter->save();
    painter->setPen(Qt::NoPen);

    painter->rotate(startAngle);
    double degRotate = (360.0 - startAngle - endAngle) / (maxValue - minValue) * (value - minValue);
    painter->rotate(degRotate);

    painter->setBrush(progressColor);
    painter->drawEllipse(-radius, radius + offset, radius * 2, radius * 2);

    painter->restore();
}

void GaugeProgress::drawPointerIndicator(QPainter *painter)
{
    if (!showPointer) {
        return;
    }

    int radius = radiusCircle - 15;
    painter->save();
    painter->setPen(Qt::NoPen);
    painter->setBrush(progressColor);

    QPolygon pts;
    pts.setPoints(3, -8, 0, 8, 0, 0, radius);

    painter->rotate(startAngle);
    double degRotate = (360.0 - startAngle - endAngle) / (maxValue - minValue) * (value - minValue);
    painter->rotate(degRotate);
    painter->drawConvexPolygon(pts);

    //Draw a central circle
    radius = radius / 4;
    painter->drawEllipse(-radius, -radius, radius * 2, radius * 2);

    painter->restore();
}

void GaugeProgress::drawPointerIndicatorR(QPainter *painter)
{
    if (!showPointer) {
        return;
    }

    int radius = radiusCircle - 15;
    painter->save();

    QPen pen;
    pen.setWidth(1);
    pen.setColor(progressColor);
    painter->setPen(pen);
    painter->setBrush(progressColor);

    QPolygon pts;
    pts.setPoints(3, -8, 0, 8, 0, 0, radius);

    painter->rotate(startAngle);
    double degRotate = (360.0 - startAngle - endAngle) / (maxValue - minValue) * (value - minValue);
    painter->rotate(degRotate);
    painter->drawConvexPolygon(pts);

    //Increase the drawing of rounded lines, overlap with previous triangles, and form rounded pointers
    pen.setCapStyle(Qt::RoundCap);
    pen.setWidthF(4);
    painter->setPen(pen);
    painter->drawLine(0, 0, 0, radius);

    //Draw a central circle
    radius = radius / 4;
    painter->drawEllipse(-radius, -radius, radius * 2, radius * 2);

    painter->restore();
}

void GaugeProgress::drawPointerTriangle(QPainter *painter)
{
    if (!showPointer) {
        return;
    }

    int radius = 20;
    int offset = radiusCircle - 25;
    painter->save();
    painter->setPen(Qt::NoPen);
    painter->setBrush(progressColor);

    QPolygon pts;
    pts.setPoints(3, -radius / 2, offset, radius / 2, offset, 0, radius + offset);

    painter->rotate(startAngle);
    double degRotate = (360.0 - startAngle - endAngle) / (maxValue - minValue) * (value - minValue);
    painter->rotate(degRotate);
    painter->drawConvexPolygon(pts);

    painter->restore();
}

void GaugeProgress::drawValue(QPainter *painter)
{
    if (!showValue) {
        return;
    }

    int radius = 100;
    painter->save();
    painter->setPen(textColor);

    QFont font;
    font.setPixelSize(showPointer ? radius - 50 : radius - 15);
    font.setBold(true);
    painter->setFont(font);

    QRectF textRect(-radius, -radius, radius * 2, radius * 2);
    QString strValue = QString("%1").arg((double)value, 0, 'f', precision);
    painter->drawText(textRect, Qt::AlignCenter, strValue);
    painter->restore();
}

Control introduction

  1. More than 140 exquisite controls, covering a variety of dashboards, progress bars, progress balls, compasses, curves, rulers, thermometers, navigation bars, navigation bars, flatui, highlight buttons, sliding selectors, lunar calendar, etc. Far more controls than qwt integrates.
  2. Each class can be separated into a separate control, zero-coupling, each control has a header file and an implementation file, independent of other files, to facilitate the integration of a single control in the form of source code into the project, less code. The control classes of qwt are interlinked and highly coupled. If you want to use one of the controls, you must include all the code.
  3. All pure Qt writing, QWidget+QPainter drawing, support any Qt version from Qt4.6 to Qt5.12, support mingw, msvc, gcc and other compilers, no scrambling, can be directly integrated into Qt Creator, as with its own controls, most of the effects can be set up only a few properties, very convenient.
  4. Each control has a corresponding separate DEMO containing the source code of the control, which is convenient for reference. It also provides an integrated DEMO for all controls.
  5. The source code of each control has detailed Chinese annotations, which are compiled in accordance with the unified design specifications. It is convenient to learn how to compile custom controls.
  6. Each control's default color matching and demo's corresponding color matching are very beautiful.
  7. More than 130 visible controls and 6 invisible controls.
  8. Some controls provide a variety of style choices, a variety of indicator style choices.
  9. All controls adapt to form stretching changes.
  10. Integrate custom control property designer, support drag design, WYSIWYG, support import and export xml format.
  11. With activex control demo, all controls can run directly in ie browser.
  12. Integrate fontawesome graphic fonts + hundreds of graphic fonts collected by Alibaba iconfont to enjoy the fun of graphic fonts.
  13. All controls finally generate a dll Dynamic Library file, which can be directly integrated into the qtcreator for dragging design use.

SDK Download

  • SDK Download Link: https://pan.baidu.com/s/1tD9v1YPfE2fgYoK6lqUr1Q Extraction code: lyhk
  • Custom Control + Property Designer Appreciation: https://pan.baidu.com/s/1l6L3rKSiLu_uYi7lnL3ibQ Extraction code: tmvl
  • The download link contains various versions of dynamic library files, the header files of all controls, using demo.
  • Custom Control Plug-in Open Dynamic Library dll (permanently free), without any backdoor and restrictions, please feel free to use.
  • At present, 22 versions of dll have been provided, including qt5.12.3 MSVC 2017 32 + 64 MinGW 32 + 64.
  • Increase control and improve control from time to time, update SDK from time to time. Welcome to make suggestions. Thank you!
  • widget version (QQ: 517216493) qml version (QQ: 373955953) camel (QQ: 278969898).

Tags: Mobile Qt Android SDK Qt5

Posted on Tue, 30 Apr 2019 08:00:37 -0700 by StroiX