在可视化应用中,弧形进度条应用也比较广泛,本文示例封装了一个可复用、个性化的弧形进度条组件。本文示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。主要结构就是外围一圈圆角进度,中间加上标题和对应进度的百分比,进度条的起始角度和结束角度可以自行调整,这样的话进度条的开口就可以在左边右边上边下边等任意位置,通过调整角度就能实现。
一、简述
本文为大家分享了QT利用QPainter实现自定义圆弧进度条组件的具体代码。绘制的核心就是drawArc函数。
二、 设计思路
主要思路:基类选择“QWidget”,使用QPainter根据图形需求画圆和圆弧,根据具体的value值旋转坐标系,达到旋转效果,旋转度数是根据value值,占比求得。最中间需要画文字上去,每次更新value时调用update()方法,重绘界面。
实现功能:
- 可设置范围
- 可设置开始旋转角度、结束旋转角度
- 可设置过度动画时常
- 可设置仪表盘标题
- 可设置背景、进度条、值、标题颜色
- 自适应窗体拉伸,文字自动缩放
三、效果
四、核心代码
1、头文件
#ifndef PROGRESSARC_H
#define PROGRESSARC_H
#include <QWidget>
struct ProgressArcPrivate;
class ProgressArc : public QWidget
{
Q_OBJECT
Q_PROPERTY(double value READ value WRITE setValue CONSTANT)
Q_PROPERTY(QString title READ title WRITE setTitle CONSTANT)
Q_PROPERTY(bool percent READ percent WRITE setPercent CONSTANT)
Q_PROPERTY(double min READ min WRITE setMin CONSTANT)
Q_PROPERTY(double max READ max WRITE setmax CONSTANT)
Q_PROPERTY(double startAngle READ startAngle WRITE setStartAngle CONSTANT)
Q_PROPERTY(double endAngle READ endAngle WRITE setEndAngle CONSTANT)
Q_PROPERTY(QColor arcColor READ arcColor WRITE setArcColor CONSTANT)
Q_PROPERTY(QColor textColor READ textColor WRITE setTextColor CONSTANT)
Q_PROPERTY(QColor titleColor READ titleColor WRITE setTitleColor CONSTANT)
Q_PROPERTY(QColor baseColor READ baseColor WRITE setBaseColor CONSTANT)
Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor CONSTANT)
public:
explicit ProgressArc(const QString &title, QWidget *parent = nullptr);
~ProgressArc();
QSize sizeHint() const override;
QSize minimumSizeHint() const override;
double value() const;
void setValue(const double value);
void setTitle(const QString &title);
QString title() const;
void setPercent(const bool percent);
bool percent() const;
void setMin(const double min);
double min() const;
void setmax(const double max);
double max() const;
void setStartAngle(const double startAngle);
double startAngle() const;
void setEndAngle(const double endAngle);
double endAngle() const;
void setArcColor(const QColor &color);
QColor arcColor() const;
void setTextColor(const QColor &color);
QColor textColor() const;
void setTitleColor(const QColor &color);
QColor titleColor() const;
void setBaseColor(const QColor &color);
QColor baseColor() const;
void setBackgroundColor(const QColor &color);
QColor backgroundColor() const;
signals:
void valueChanged(const double value);
private slots:
void onStartAnimation(const double value);
protected:
void paintEvent(QPaintEvent *event) override;
private:
void drawArc(QPainter *painter);
void drawText(QPainter *painter);
QScopedPointer<ProgressArcPrivate> d;
};
#endif // PROGRESSARC_H
2、实现代码
#include "progressarc.h"
#include <QPainter>
#include <QPropertyAnimation>
struct ProgressArcPrivate{
double minValue = 0;
double maxValue = 100;
double value = 0;
double startAngle = -90;
double endAngle = 270;
QColor arcColor = QColor(QLatin1String("#4da1ff"));
QColor textColor = QColor(QLatin1String("#4da1ff"));
QColor titleColor = QColor(80, 80, 80);
QColor baseColor = QColor(179,179,179);
QColor backgroundColor = Qt::transparent;
bool percent = true;
QString title;
QPropertyAnimation *animation;
};
ProgressArc::ProgressArc(const QString &title, QWidget *parent)
: QWidget(parent)
, d(new ProgressArcPrivate)
{
setTitle(title);
d->animation = new QPropertyAnimation(this, "value", this);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
connect(this, &ProgressArc::valueChanged, this, &ProgressArc::onStartAnimation);
}
ProgressArc::~ProgressArc()
{
}
void ProgressArc::setTitle(const QString &title)
{
d->title = title;
update();
}
QString ProgressArc::title() const
{
return d->title;
}
void ProgressArc::setPercent(const bool percent)
{
d->percent = percent;
update();
}
bool ProgressArc::percent() const
{
return d->percent;
}
void ProgressArc::setMin(const double min)
{
d->minValue = min;
update();
}
double ProgressArc::min() const
{
return d->minValue;
}
void ProgressArc::setmax(const double max)
{
d->maxValue = max;
update();
}
double ProgressArc::max() const
{
return d->maxValue;
}
void ProgressArc::setStartAngle(const double startAngle)
{
d->startAngle = startAngle;
update();
}
double ProgressArc::startAngle() const
{
return d->startAngle;
}
void ProgressArc::setEndAngle(const double endAngle)
{
d->endAngle = endAngle;
update();
}
double ProgressArc::endAngle() const
{
return d->endAngle;
}
void ProgressArc::setArcColor(const QColor &color)
{
d->arcColor = color;
update();
}
QColor ProgressArc::arcColor() const
{
return d->arcColor;
}
void ProgressArc::setTextColor(const QColor &color)
{
d->textColor = color;
update();
}
QColor ProgressArc::textColor() const
{
return d->textColor;
}
void ProgressArc::setTitleColor(const QColor &color)
{
d->titleColor = color;
update();
}
QColor ProgressArc::titleColor() const
{
return d->titleColor;
}
void ProgressArc::setBaseColor(const QColor &color)
{
d->baseColor = color;
update();
}
QColor ProgressArc::baseColor() const
{
return d->baseColor;
}
void ProgressArc::setBackgroundColor(const QColor &color)
{
d->backgroundColor = color;
update();
}
QColor ProgressArc::backgroundColor() const
{
return d->backgroundColor;
}
QSize ProgressArc::sizeHint() const
{
return QSize(200, 200);
}
QSize ProgressArc::minimumSizeHint() const
{
return QSize(80, 80);
}
void ProgressArc::paintEvent(QPaintEvent *event)
{
QWidget::paintEvent(event);
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
// 背景
if (d->backgroundColor != Qt::transparent) {
painter.setPen(Qt::NoPen);
painter.fillRect(rect(), d->backgroundColor);
}
// 平移中心
painter.translate(width() / 2, height() / 2);
// 圆弧
drawArc(&painter);
// text
drawText(&painter);
}
void ProgressArc::onStartAnimation(const double value)
{
if(value < d->minValue
|| value > d->maxValue
|| value == d->value)
return;
int start = d->value;
int end = value;
d->animation->setStartValue(start);
d->animation->setEndValue(end);
d->animation->start();
}
double ProgressArc::value() const
{
return d->value;
}
void ProgressArc::setValue(const double value)
{
d->value = value;
update();
}
void ProgressArc::drawArc(QPainter *painter)
{
double min = qMin(width(), height());
double arcWidth = min / 10.0;
double radius = min / 2.0 - arcWidth - 5;
QRectF rect = QRectF(-radius, -radius, radius * 2, radius * 2);
QPen pen;
pen.setWidthF(arcWidth);
pen.setCapStyle(Qt::RoundCap);
// 圆弧背景
double angle = d->endAngle - d->startAngle;
pen.setColor(d->baseColor);
painter->setPen(pen);
painter->drawArc(rect, d->startAngle * 16, angle * 16);
// 圆弧进度
double spanAngle = angle * ((d->value - d->minValue) / (d->maxValue - d->minValue));
double startAngle = d->endAngle - spanAngle;
pen.setColor(d->arcColor);
painter->setPen(pen);
painter->drawArc(rect, startAngle * 16, spanAngle * 16);
}
void ProgressArc::drawText(QPainter *painter)
{
double min = qMin(width(), height());
double arcWidth = min / 10.0;
double radius = min / 2.0 - arcWidth - 5;
painter->setPen(d->textColor);
QFont font("Microsoft YaHei", radius / 4.0);
painter->setFont(font);
QString strValue;
if (d->percent) {
double temp = d->value / (d->maxValue - d->minValue) * 100;
strValue = QString("%1%").arg(temp, 0, 'f', 2);
} else
strValue = QString("%1").arg(d->value, 0, 'f', 2);
// value
QRectF valueRect(-radius, 0, radius * 2, radius / 3);
painter->drawText(valueRect, Qt::AlignCenter, strValue);
painter->setPen(d->titleColor);
font.setPixelSize(radius / 4.0);
painter->setFont(font);
// title
QRectF textRect(-radius, -radius / 2.5, radius * 2, radius / 3);
painter->drawText(textRect, Qt::AlignCenter, d->title);
}
以上是圆弧进度条组件实现代码,在实际使用中,可以根据需要自定义动画文件和样式。
该自定义控件主要特点有:
1、纯QPaint绘制,不包括图片等文件;
2、多种自定义控制,非常灵活;
3、能够自适应大小,不需要手动调整;
4、支持动画效果。
需要注意的是,在使用QPainter实现自定义圆弧进度条组件时,需要灵活运用QPainter的绘图函数和提供给用户的交互函数,并注意处理用户的交互操作和组件的尺寸调整等问题。
五、使用示例
以下是一个简单的示例代码,演示了如何在Qt中使用此控件:
#include "mainwindow.h"
#include "progressarc.h"
#include <QtWidgets>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QSlider *slider = new QSlider(this);
slider->setRange(0, 100);
ProgressArc *progressArc1 = new ProgressArc(tr("赞成"), this);
connect(slider, &QSlider::valueChanged, progressArc1, &ProgressArc::valueChanged);
ProgressArc *progressArc2 = new ProgressArc(tr("反对"), this);
progressArc2->setArcColor(QColor(250, 118, 113));
progressArc2->setStartAngle(-50);
progressArc2->setEndAngle(230);
connect(slider, &QSlider::valueChanged, progressArc2, &ProgressArc::valueChanged);
ProgressArc *progressArc3 = new ProgressArc(tr("弃权"), this);
progressArc3->setArcColor(QColor(41, 197, 90));
progressArc3->setStartAngle(-140);
progressArc3->setEndAngle(140);
connect(slider, &QSlider::valueChanged, progressArc3, &ProgressArc::valueChanged);
QWidget *widget = new QWidget(this);
QHBoxLayout *layout = new QHBoxLayout(widget);
layout->addWidget(progressArc1);
layout->addWidget(progressArc2);
layout->addWidget(progressArc3);
layout->addWidget(slider);
setCentralWidget(widget);
resize(670, 260);
}
MainWindow::~MainWindow()
{
}
总结一下,圆弧进度条组件的设计方法和流程如下:
-
定义组件的功能和需求:确定组件需要实现的功能,例如显示进度、设置颜色等。
-
设计组件的外观:确定圆弧的样式,包括颜色、宽度、起始角度等。
-
创建组件的类:根据需求,创建一个新的类来实现组件的功能。
-
实现组件的逻辑:在组件的类中,编写代码来处理用户的输入和显示组件的状态。
-
测试组件的功能:使用测试数据来验证组件是否正常工作,并修复可能存在的问题。
谢谢您的关注和阅读!如有任何问题或需要帮助,请随时与我联系。希望您能继续支持并享受更多精彩的内容。祝您生活愉快!