深圳大浪网站建设,杭州seo博客,河南建设集团有限公司,企业培训机构有哪些如何在Qt中绘制一个弧形的进度条
在图形用户界面开发中#xff0c;进度指示控件#xff08;Progress Widget#xff09;是非常常见且实用的组件。CCArcProgressWidget 是一个继承自 QWidget 的自定义控件#xff0c;用于绘制圆弧形进度条。当然#xff0c;笔者看了眼公开…如何在Qt中绘制一个弧形的进度条
在图形用户界面开发中进度指示控件Progress Widget是非常常见且实用的组件。CCArcProgressWidget 是一个继承自 QWidget 的自定义控件用于绘制圆弧形进度条。当然笔者看了眼公开的实现基本上都非常完善了笔者在这里添加了一个更好的动画。 类定义概览
CCArcProgressWidget 类定义在 CCArcProgressWidget.h 中使用 Qt 元对象系统通过 Q_OBJECT 宏启用信号与属性机制。该控件支持如下属性绑定
value当前进度值maxValue最大进度值displayValue动画过程中的显示值与实际 value 异步
这些属性可被 QML 或动画机制绑定便于动态效果的呈现。笔者这里使用的是Q_PROPERTY属性系统公开的所以QML可用笑
静态常量定义这部分是笔者认为编译的时候可以指定的
类中定义了多个静态常量用于控制组件的外观与行为
DURATION动画持续时间单位毫秒默认为 500msARC_WIDTH圆弧的线宽默认为 50 像素DEFAULT_VALUE默认初始值为 0DEFAULT_MAX默认最大值为 100DEF_TEXT_COLOR默认文本颜色DEF_BKCOLOR默认背景弧颜色未完成部分DEF_ARC_COLOR默认进度弧颜色已完成部分
这些常量使得控件具有清晰的默认状态便于使用和维护。
属性访问与设置接口
该类提供了一系列 inline 内联函数和公开接口用于读取与设置进度值及外观样式
int value() const获取当前进度值void setValue(int val)设置当前进度值含动画int maxValue() const获取最大值void setMaxValue(int max)设置最大值QColor progressArcColor() const / void setProgressArcColor(const QColor)读取与设置进度弧颜色QColor progressBackgroundColor() const / void setProgressBackgroundColor(const QColor)读取与设置背景弧颜色QColor progressTextColor() const / void setProgressTextColor(const QColor)读取与设置文本颜色
所有设置函数内部均会判断是否真正发生变化避免无谓的刷新若发生更改则调用 update() 触发重绘。
信号机制
该控件定义了三个信号
valueChanged(int)当用户设置新进度值时发出maxValueChanged(int)当最大值被重新设置时发出displayValueChanged(int)当动画中显示的值发生变化时发出
这些信号便于其他模块如界面展示、数据记录实时响应进度的变化。
绘制函数与动画支持
该类重载了 paintEvent 事件处理函数实现核心绘制逻辑。绘制内容包括三部分
背景弧通过 drawBackgroundArc() 绘制未完成部分进度弧通过 drawProgressArc() 根据当前动画角度绘制完成部分中心文本通过 drawText() 绘制当前数值或状态文字
同时setupAnimation() 函数用于构建 QPropertyAnimation 动画使 value 到 displayValue 之间具备平滑过渡效果。动画期间实际值不变仅 displayValue 动态变化从而提升用户体验。
私有成员变量
类中使用了如下私有成员保存状态
progress_value当前进度值progress_display_value当前显示值用于动画progress_max_value最大进度值progress_minAngle 与 progress_startAngle控制弧线的起始与方向默认从顶部顺时针progress_arc_color、progress_backgroundColor、progress_textColor颜色配置QPropertyAnimation* animation动画对象指针
这些成员变量共同构成了进度显示的完整状态。
使用示例简要
CCArcProgressWidget* widget new CCArcProgressWidget(this);
widget-setValue(70);
widget-setMaxValue(100);
widget-setProgressArcColor(Qt::blue);
widget-setProgressBackgroundColor(Qt::lightGray);
widget-setProgressTextColor(Qt::black);以上代码将在界面中创建一个蓝色的圆形进度条表示当前进度为 70%。
一些实现的细节说明
下面的部分是属性设置的接口没什么有趣的。
#include CCArcProgressWidget.h
#include QPropertyAnimationCCArcProgressWidget::CCArcProgressWidget(QWidget* parent): QWidget { parent } {setupAnimation();
}void CCArcProgressWidget::setupAnimation() {animation new QPropertyAnimation(this, displayValue);animation-setDuration(DURATION);animation-setEasingCurve(QEasingCurve::OutCubic);
}void CCArcProgressWidget::setValue(int val) {val qBound(0, val, progress_max_value);if (val progress_value) // avoid duplicate animationsreturn;progress_value val;animation-stop();animation-setStartValue(progress_display_value);animation-setEndValue(progress_value);animation-start();
} 下面说下我们的绘制这里是每一次触发重绘的时候我们的设备实际上进行的绘制。
void CCArcProgressWidget::paintEvent(QPaintEvent* event [[maybe_unused]]) {QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing, true);QRectF baseRect rect();double side qMin(baseRect.width(), baseRect.height());// 到这里是为了获取绘制成正方形而不是椭圆形不然太难看了QRectF squareRect((baseRect.width() - side) / 2.0,(baseRect.height() - side) / 2.0,side, side);int margin ARC_WIDTH 5;QRectF arcRect squareRect.adjusted(margin, margin, -margin, -margin);double radius qMin(arcRect.width(), arcRect.height()) / 2;QPointF center arcRect.center();double angle 360.0 * progress_display_value / progress_max_value;angle qMaxdouble(progress_minAngle, -angle);drawBackgroundArc(painter, arcRect);drawProgressArc(painter, arcRect, angle);drawText(painter, center, radius);
}paintEvent 事件首先确定绘制区域 arcRect再根据当前 displayValue 计算对应的角度 angle。之后依次调用
drawBackgroundArc用圆弧绘制背景轨迹。drawProgressArc绘制当前进度的圆弧同时在圆弧末端绘制小圆点增强视觉效果。drawText居中绘制当前进度的百分比文本。
void CCArcProgressWidget::drawBackgroundArc(QPainter painter, const QRectF arcRect) {QPen pen(progress_backgroundColor, ARC_WIDTH);pen.setCapStyle(Qt::RoundCap);painter.setPen(pen);painter.drawArc(arcRect, progress_startAngle * 16, 360 * 16);
}void CCArcProgressWidget::drawProgressArc(QPainter painter, const QRectF arcRect, double angle) {if (angle 0)return;QConicalGradient gradient(arcRect.center(), progress_startAngle);gradient.setColorAt(0, progress_arc_color.lighter(150));gradient.setColorAt(0.5, progress_arc_color);gradient.setColorAt(1, progress_arc_color.darker(150));QPen pen(QBrush(gradient), ARC_WIDTH);pen.setCapStyle(Qt::FlatCap);painter.setPen(pen);painter.drawArc(arcRect, progress_startAngle * 16, -angle * 16);double spanAngleRad qDegreesToRadians(progress_startAngle - angle);double cx arcRect.center().x();double cy arcRect.center().y();double rx arcRect.width() / 2;double ry arcRect.height() / 2;double ex cx rx * qCos(spanAngleRad);double ey cy - ry * qSin(spanAngleRad);QBrush brush(gradient);painter.setBrush(brush);painter.setPen(Qt::NoPen);painter.drawEllipse(QPointF(ex, ey), ARC_WIDTH / 2.0, ARC_WIDTH / 2.0);
}void CCArcProgressWidget::drawText(QPainter painter, const QPointF center, double radius) {painter.setFont(QFont(Arial, radius * 0.3, QFont::Bold));painter.setPen(progress_textColor);QString text QString(%1%).arg(qRound(100.0 * progress_display_value / progress_max_value));QRectF textRect(center.x() - radius, center.y() - radius,radius * 2, radius * 2);painter.drawText(textRect, Qt::AlignCenter, text);
}