查看: 242|回复: 0

Python+Slint圆形进度条:Path与ArcTo圆弧计算

[复制链接]
发表于 2 小时前 | 显示全部楼层 |阅读模式
在 Slint 中做圆形进度条,核心不是用图片或 Canvas 逐帧绘制,而是用 Path 组合 MoveTo、ArcTo 两个路径命令,把 progress 值映射成圆弧终点坐标。原文给出的实现包含 Python 启动入口、Slint 界面结构、圆弧角度换算、满圆边界处理、动画、Timer 自动演示以及滑块双向绑定,适合用作桌面端 Python + Slint 的自定义控件练习。下面按工程入口、圆弧实现、边界与交互几个部分重组说明。

一、工程入口与运行方式
原文工程至少包含 main.py 和 main.slint 两个文件。main.py 只负责加载 Slint 文件并运行主窗口:
  1. # -*- coding: utf-8 -*-
  2. import slint
  3. ui = slint.load_file("main.slint")
  4. window = ui.MainWindow()
  5. window.run()
复制代码
这里 load_file("main.slint") 使用相对路径,运行时应保证工作目录或文件位置能正确解析到 main.slint。MainWindow 在 main.slint 中导出,Python 侧通过 ui.MainWindow() 实例化窗口,再调用 run() 进入事件循环。

二、界面属性与动画基础
MainWindow 继承 Window,并声明 progress 和 auto-play 两个属性。progress 取值 0.0~1.0,默认 0.35;auto-play 控制自动演示是否开启。动画通过 animate 关键字绑定到 progress:
  1. property <float> progress: 0.35;
  2. property <bool> auto-play: false;
  3. animate progress { duration: 200ms; easing: ease-in-out; }
复制代码
当 progress 被滑块、按钮或 Timer 修改时,Slint 会在 200ms 内按 ease-in-out 过渡,而不是立即跳变。这个细节对进度条观感很关键,因为圆弧长度和中心百分比文字都会随 progress 变化。

三、圆形区域的尺寸与坐标系统
圆形进度条放在一个 Rectangle 中。代码用 diameter 计算圆直径,取容器宽高较小值的 0.75,再用 ring-x、ring-y 把圆居中。Path 使用 viewbox-width: 200、viewbox-height: 200 的坐标系统,所以圆弧坐标按 0~200 计算,而不是直接按实际像素计算;stroke-width: 12px 控制圆环线宽,fill: transparent 表示只描边不填充。

四、ArcTo 圆弧终点计算
进度圆弧起点固定在正上方 (100,0)。progress 乘以 360 得到角度,再减 90 是因为要把起点偏移到以顶部为起点的坐标系中。终点坐标由 cos/sin 计算,下面片段同时包含背景轨道之外的关键进度圆弧逻辑:
  1. Path {
  2.     x: parent.ring-x;
  3.     y: parent.ring-y;
  4.     width: parent.diameter;
  5.     height: parent.diameter;
  6.     viewbox-width: 200;
  7.     viewbox-height: 200;
  8.     stroke-width: 12px;
  9.     stroke: #06b6d4;
  10.     fill: transparent;
  11.     visible: progress > 0.005 && progress < 0.995;
  12.     MoveTo { x: 100; y: 0; }
  13.     ArcTo {
  14.         x: 100 + 100 * cos((progress * 360.0 - 90.0) * 1deg);
  15.         y: 100 + 100 * sin((progress * 360.0 - 90.0) * 1deg);
  16.         radius-x: 100;
  17.         radius-y: 100;
  18.         large-arc: progress > 0.5;
  19.         sweep: true;
  20.     }
  21. }
复制代码
ArcTo 参数含义:x/y 是终点坐标;radius-x/radius-y 是椭圆弧半径;large-arc 表示是否走大于 180° 的大弧;sweep 表示绘制方向。progress=0.5 时角度为 90°,正好半圆;progress>0.5 时圆弧超过半圆,因此 large-arc 设为 true,否则 ArcTo 会选择较短弧段。progress=1.0 时角度为 270°,如果直接依赖单个 ArcTo,终点与起点重合会导致圆弧长度为 0,这也是需要单独处理满圆的原因。

五、边界处理:0、满圆和可见性
原文用 visible 把动态进度圆弧限制在 progress > 0.005 且 progress < 0.995 的区间。低于下限时只显示背景轨道;达到上限时隐藏动态圆弧,改用两段半圆弧拼接成完整圆环。满圆覆盖代码与背景轨道绘制方式一致:
  1. Path {
  2.     x: parent.ring-x;
  3.     y: parent.ring-y;
  4.     width: parent.diameter;
  5.     height: parent.diameter;
  6.     viewbox-width: 200;
  7.     viewbox-height: 200;
  8.     stroke-width: 12px;
  9.     stroke: #06b6d4;
  10.     fill: transparent;
  11.     visible: progress >= 0.995;
  12.     MoveTo { x: 100; y: 0; }
  13.     ArcTo {
  14.         x: 100; y: 200;
  15.         radius-x: 100; radius-y: 100;
  16.         large-arc: false; sweep: true;
  17.     }
  18.     ArcTo {
  19.         x: 100; y: 0;
  20.         radius-x: 100; radius-y: 100;
  21.         large-arc: false; sweep: true;
  22.     }
  23. }
复制代码
这种处理避免了 ArcTo 在起点终点重合时画不出完整圆的问题,也让接近 0 或接近 1 的边界状态有明确显示逻辑。

六、自动演示与正弦映射
Timer 每 30ms 触发一次,running 绑定 auto-play。触发时通过 sin 计算新进度:
  1. Timer {
  2.     interval: 30ms;
  3.     running: auto-play;
  4.     triggered => {
  5.         root.progress = (sin((root.progress * 360.0 + 3.0) * 1deg) + 1.0) * 0.5;
  6.     }
  7. }
复制代码
这行代码把 progress 先映射到角度,再用 sin 得到 -1~1,随后加 1 乘 0.5 映射到 0~1。结合 animate progress 的 200ms 动画,自动演示不是硬切,而是平滑摆动。注意 Timer 的 interval 和 animate 的 duration 是两套时间参数:前者决定触发频率,后者决定属性变化的过渡时间。

七、滑块、按钮与双向绑定
滑块 value 与 slider-val 双向绑定,slider-val 又由 root.progress * 100.0 定义,因此滑块 0~100 对应进度 0%~100%:
  1. property <float> slider-val: root.progress * 100.0;
  2. Slider {
  3.     minimum: 0.0;
  4.     maximum: 100.0;
  5.     value <=> slider-val;
  6. }
复制代码
按钮直接设置 root.progress 为 0.0、0.25、0.50、0.75、1.0,用于快捷跳转。中心文字通过 round(progress * 100) 拼接百分号显示。由于圆弧、文字、滑块都依赖同一个 progress 属性,交互链路比较集中,排查时应优先检查 progress 是否被正确更新,以及 slider-val 双向绑定是否形成循环赋值或单位换算错误。

八、适用场景与实现取舍
这套实现依赖 Slint 的矢量 Path 和 ArcTo,不需要贴图或 Canvas 逐帧绘制,缩放时不会失真,代码量也集中在路径参数和属性绑定上。适合桌面工具、下载/安装进度、任务完成度等需要圆形进度反馈的界面。需要留意的兼容性细节包括:Slint 版本是否支持所用 Path/ArcTo 属性、角度单位是否写成 1deg、large-arc 在 progress>0.5 时的切换、满圆边界 0.995 与 0.005 的阈值,以及 load_file 的相对路径解析。按原文思路排错时,可以先确认 progress 是否在 0~1 内,再检查 ArcTo 终点坐标、large-arc 和 visible 条件是否与当前进度匹配。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-10-21 12:59 , Processed in 0.026587 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部