如何在Qt中绘制一个带有动画的弧形进度条?

news2025/7/22 15:13:44

如何在Qt中绘制一个弧形的进度条

在图形用户界面开发中,进度指示控件(Progress Widget)是非常常见且实用的组件。CCArcProgressWidget 是一个继承自 QWidget 的自定义控件,用于绘制圆弧形进度条。当然,笔者看了眼公开的实现,基本上都非常完善了,笔者在这里添加了一个更好的动画。

在这里插入图片描述

类定义概览

CCArcProgressWidget 类定义在 CCArcProgressWidget.h 中,使用 Qt 元对象系统,通过 Q_OBJECT 宏启用信号与属性机制。该控件支持如下属性绑定:

  • value:当前进度值
  • maxValue:最大进度值
  • displayValue:动画过程中的显示值(与实际 value 异步)

这些属性可被 QML 或动画机制绑定,便于动态效果的呈现。(笔者这里使用的是Q_PROPERTY属性系统公开的,所以QML可用(笑))

静态常量定义(这部分是笔者认为编译的时候可以指定的)

类中定义了多个静态常量,用于控制组件的外观与行为:

  • DURATION:动画持续时间(单位:毫秒),默认为 500ms
  • ARC_WIDTH:圆弧的线宽,默认为 50 像素
  • DEFAULT_VALUE:默认初始值,为 0
  • DEFAULT_MAX:默认最大值,为 100
  • DEF_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 动画,使 valuedisplayValue 之间具备平滑过渡效果。动画期间实际值不变,仅 displayValue 动态变化,从而提升用户体验。

私有成员变量

类中使用了如下私有成员保存状态:

  • progress_value:当前进度值
  • progress_display_value:当前显示值(用于动画)
  • progress_max_value:最大进度值
  • progress_minAngleprogress_startAngle:控制弧线的起始与方向(默认从顶部顺时针)
  • progress_arc_colorprogress_backgroundColorprogress_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 <QPropertyAnimation>

CCArcProgressWidget::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 animations
		return;

	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 = qMax<double>(progress_minAngle, -angle);

	drawBackgroundArc(painter, arcRect);
	drawProgressArc(painter, arcRect, angle);
	drawText(painter, center, radius);
}
  1. 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);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2394845.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

国产三维CAD皇冠CAD(CrownCAD)建模教程:汽车电池

在线解读『汽车电池』的三维建模流程&#xff0c;讲解3D草图、保存实体、拉伸凸台/基体、设置外观等操作技巧&#xff0c;一起和皇冠CAD&#xff08;CrownCAD&#xff09;学习制作步骤吧&#xff01; 汽车电池&#xff08;通常指铅酸蓄电池或锂离子电池&#xff09;是车辆电气系…

VMware-workstation安装教程--超详细(附带安装包)附带安装CentOS系统教程

VMware-workstation安装教程--超详细&#xff08;附带安装包&#xff09;附带安装CentOS系统教程 一、下载软件VMwware二、下载需要的镜像三、在VMware上安装系统 一、下载软件VMwware 二、下载需要的镜像 三、在VMware上安装系统 VMware 被 Broadcom&#xff08;博通&#x…

2025年- H63-Lc171--33.搜索旋转排序数组(2次二分查找,需二刷)--Java版

1.题目描述 2.思路 输入&#xff1a;旋转后的数组 nums&#xff0c;和一个整数 target 输出&#xff1a;target 在 nums 中的下标&#xff0c;如果不存在&#xff0c;返回 -1 限制&#xff1a;时间复杂度为 O(log n)&#xff0c;所以不能用遍历&#xff0c;必须使用 二分查找…

3D-激光SLAM笔记

目录 定位方案 编译tbb ros2humble安装 命令 colcon commond not found 栅格地图生成&#xff1a; evo画轨迹曲线 安装gtsam4.0.2 安装ceres-solver1.14.0 定位方案 1 方案一&#xff1a;改动最多 fasterlio 建图&#xff0c;加闭环优化&#xff0c;参考fast-lio增加关…

HomeKit 基本理解

概括 HomeKit 将用户的家庭自动化信息存储在数据库中&#xff0c;该数据库由苹果的内置iOS家庭应用程序、支持HomeKit的应用程序和其他开发人员的应用程序共享。所有这些应用程序都使用HomeKit框架作为对等程序访问数据库. Home 只是相当于 HomeKit 的表现层,其他应用在实现 …

(LeetCode 每日一题) 909. 蛇梯棋 (广度优先搜索bfs)

题目&#xff1a;909. 蛇梯棋 思路&#xff1a;广度优先搜索bfs队列&#xff0c;时间复杂度0(6*n^2)。 细节看注释 C版本&#xff1a; class Solution { public:int snakesAndLadders(vector<vector<int>>& board) {int nboard.size();// vis[i]&#xff1a;…

生成https 证书步骤

一、OpenSSL下载 OpenSSL下载地址&#xff1a; https://slproweb.com/products/Win32OpenSSL.html 如果电脑是64位的就选择64位的 二、OpenSSL安装 双击打开.exe文件 开始安装&#xff0c;一直下一步&#xff0c;不过需要注意的是默认安装路径是C盘&#xff0c;可更改到其他盘…

设计模式——适配器设计模式(结构型)

摘要 本文详细介绍了适配器设计模式&#xff0c;包括其定义、核心思想、角色、结构、实现方式、适用场景及实战示例。适配器模式是一种结构型设计模式&#xff0c;通过将一个类的接口转换成客户端期望的另一个接口&#xff0c;解决接口不兼容问题&#xff0c;提高系统灵活性和…

小黑大语言模型通过设计demo进行应用探索:langchain中chain的简单理解demo

chain简介 LangChain 中的 Chain 模块‌在开发大型语言模型&#xff08;LLM&#xff09;驱动的应用程序中起着至关重要的作用。Chain是串联LLM能力与实际业务的关键桥梁&#xff0c;通过将多个工具和模块按逻辑串联起来&#xff0c;实现复杂任务的多步骤流程编排。 案例 通过…

秒杀系统—5.第二版升级优化的技术文档三

大纲 8.秒杀系统的秒杀库存服务实现 9.秒杀系统的秒杀抢购服务实现 10.秒杀系统的秒杀下单服务实现 11.秒杀系统的页面渲染服务实现 12.秒杀系统的页面发布服务实现 8.秒杀系统的秒杀库存服务实现 (1)秒杀商品的库存在Redis中的结构 (2)库存分片并同步到Redis的实现 (3…

【STM32】HAL库 之 CAN 开发指南

基于stm32 f407vet6芯片 使用hal库开发 can 简单讲解一下can的基础使用 CubeMX配置 这里打开CAN1 并且设置好波特率和NVIC相关的配置 波特率使用波特率计算器软件 使用采样率最高的这段 填入 得到波特率1M bit/s 然后编写代码 环形缓冲区 #include "driver_buffer.h&qu…

DeepSeek R1-0528 新开源推理模型(免费且快速)

DeepSeek推出了新模型,但这不是R2! R1-0528是DeepSeek的最新模型,在发布仅数小时后就在开源社区获得了巨大关注。 这个悄然发布的模型DeepSeek R1-0528,已经开始与OpenAI的o3一较高下。 让我来详细介绍这次更新的新内容。 DeepSeek R1-0528 发布 DeepSeek在这次发布中采…

Go 语言的 GC 垃圾回收

序言 垃圾回收&#xff08;Garbage Collection&#xff0c;简称 GC&#xff09;机制 是一种自动内存管理技术&#xff0c;主要用于在程序运行时自动识别并释放不再使用的内存空间&#xff0c;防止内存泄漏和不必要的资源浪费。这篇文章让我们来看一下 Go 语言的垃圾回收机制是如…

安全帽目标检测

安全帽数据集 这里我们使用的安全帽数据集是HelmentDetection&#xff0c;这是一个公开数据集&#xff0c;里面包含5000张voc标注格式的图像&#xff0c;分为三个类别&#xff0c;分别是 0: head 1: helmet 2: person 安全帽数据集下载地址、 我们将数据集下载后&#xff0c…

Eclipse 插件开发 5.3 编辑器 监听输入

Eclipse 插件开发 5.3 编辑器监 听输入 1 插件配置2 添加监听3 查看效果 Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Click1 Bundle-SymbolicName: com.xu.click1;singleton:true Bundle-Version: 1.0.0 Bundle-Activator: com.xu.click1.Activator Bundle…

iOS 集成网易云信IM

云信官方文档在这 看官方文档的时候&#xff0c;版本选择最新的V10。 1、CocoPods集成 pod NIMSDK_LITE 2、AppDelegate.m添加头文件 #import <NIMSDK/NIMSDK.h> 3、初始化 NIMSDKOption *mrnn_option [NIMSDKOption optionWithAppKey:"6f6568e354026d2d658a…

azure web app创建分步指南系列之二

为注册表授权托管标识 你创建的托管标识尚未获得从容器注册表中提取数据的授权。在此步骤中,你将启用授权。 返回容器注册表的管理页面: 在左侧导航菜单中,选择“访问控制 (IAM)”。选择“添加角色分配”。此屏幕截图显示了如何为容器注册表启用添加角色分配。在角色列表中…

题海拾贝:P8598 [蓝桥杯 2013 省 AB] 错误票据

Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《数据结构与算法之美》、《题海拾贝》 欢迎点赞&#xff0c;关注&#xff01; 1、题…

Python量化交易12——Tushare全面获取各种经济金融数据

两年前写过Tushare的简单使用&#xff1a; Python量化交易08——利用Tushare获取日K数据_skshare- 现在更新一下吧&#xff0c;这两年用过不少的金融数据库&#xff0c;akshare&#xff0c;baostock&#xff0c;雅虎的&#xff0c;pd自带的......发现还是Tushare最稳定最好用&…

封装一个小程序选择器(可多选、单选、搜索)

组件 <template><view class"popup" v-show"show"><view class"bg" tap"cancelMultiple"></view><view class"selectMultiple"><view class"multipleBody"><view class&…