圆环加载效果

效果预览

代码实现

from PyQt5.QtCore import QSize, pyqtProperty, QTimer, Qt, QThread, pyqtSignal
from PyQt5.QtGui import QColor, QPainter
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QPushButton, QVBoxLayout, QLabel, QGridLayoutclass CircleProgressBar(QWidget):Color = QColor(37, 162, 208)  # 圆圈颜色Clockwise = True  # 顺时针还是逆时针Delta = 36def __init__(self, *args, color=None, clockwise=True, **kwargs):super(CircleProgressBar, self).__init__(*args, **kwargs)self.angle = 0self.Clockwise = clockwiseif color:self.Color = colorself._timer = QTimer(self, timeout=self.update)def start(self):"""启动进度条的加载动画"""self._timer.start(100)  # 开始定时器def stop(self):"""停止进度条的加载动画并删除控件"""self._timer.stop()self.deleteLater()  # 删除控件并释放资源def paintEvent(self, event):super(CircleProgressBar, self).paintEvent(event)painter = QPainter(self)painter.setRenderHint(QPainter.Antialiasing)painter.translate(self.width() / 2, self.height() / 2)side = min(self.width(), self.height())painter.scale(side / 100.0, side / 100.0)painter.rotate(self.angle)painter.save()painter.setPen(Qt.NoPen)color = self.Color.toRgb()for i in range(11):color.setAlphaF(1.0 * i / 10)painter.setBrush(color)painter.drawEllipse(30, -10, 20, 20)painter.rotate(36)painter.restore()self.angle += self.Delta if self.Clockwise else -self.Deltaself.angle %= 360@pyqtProperty(QColor)def color(self) -> QColor:return self.Color@color.setterdef color(self, color: QColor):if self.Color != color:self.Color = colorself.update()@pyqtProperty(bool)def clockwise(self) -> bool:return self.Clockwise@clockwise.setterdef clockwise(self, clockwise: bool):if self.Clockwise != clockwise:self.Clockwise = clockwiseself.update()@pyqtProperty(int)def delta(self) -> int:return self.Delta@delta.setterdef delta(self, delta: int):if self.delta != delta:self.delta = deltaself.update()def sizeHint(self) -> QSize:return QSize(100, 100)class LoadingThread(QThread):"""模拟加载过程的线程"""finished = pyqtSignal()def run(self):# 在这里模拟加载过程,可以替换为实际的加载逻辑import timetime.sleep(5)  # 模拟加载时间self.finished.emit()  # 加载完成后发出信号class CustomWidget(QWidget):"""每个子控件,包含两个按钮"""def __init__(self, main_window, bg_color, *args, **kwargs):super(CustomWidget, self).__init__(*args, **kwargs)self.main_window = main_windowlayout = QVBoxLayout(self)# Set the background color for this widgetself.setStyleSheet(f"background-color: {bg_color};")# Button to trigger loading animation in the main UIself.centerLoadButton = QPushButton("主UI中居中加载")self.centerLoadButton.clicked.connect(self.startLoadingInMain)layout.addWidget(self.centerLoadButton)# Button to trigger loading animation in this widgetself.localLoadButton = QPushButton("本控件中加载")self.localLoadButton.clicked.connect(self.startLoadingInLocal)layout.addWidget(self.localLoadButton)def startLoadingInMain(self):"""在主窗口的中心显示加载动画"""self.main_window.startLoadingInCenter()def startLoadingInLocal(self):"""在本控件内部显示加载动画"""self.main_window.startLoadingInWidget(self)class Window(QWidget):def __init__(self, *args, **kwargs):super(Window, self).__init__(*args, **kwargs)self.initUI()def initUI(self):layout = QGridLayout(self)self.setLayout(layout)# 创建四个子控件,并为每个控件指定不同的背景颜色widget1 = CustomWidget(self, "lightblue")widget2 = CustomWidget(self, "lightgreen")widget3 = CustomWidget(self, "lightcoral")widget4 = CustomWidget(self, "lightyellow")layout.addWidget(widget1, 0, 0)layout.addWidget(widget2, 0, 1)layout.addWidget(widget3, 1, 0)layout.addWidget(widget4, 1, 1)def startLoadingInCenter(self):"""在主窗口中心显示加载动画"""self.progressBar = CircleProgressBar(self)  # 动态创建进度条self.progressBar.setFixedSize(100, 100)self.progressBar.show()# 设置进度条在主窗口中心self.progressBar.move(self.width() // 2 - self.progressBar.width() // 2,self.height() // 2 - self.progressBar.height() // 2)self.progressBar.start()  # 手动启动进度条动画# 启动加载线程self.loadingThread = LoadingThread()self.loadingThread.finished.connect(self.progressBar.stop)self.loadingThread.start()def startLoadingInWidget(self, widget):"""在指定的小部件内显示加载动画"""self.progressBar = CircleProgressBar(widget)  # 在小部件中创建进度条self.progressBar.setFixedSize(50, 50)self.progressBar.show()# 设置进度条在小部件中心self.progressBar.move(widget.width() // 2 - self.progressBar.width() // 2,widget.height() // 2 - self.progressBar.height() // 2)self.progressBar.start()  # 手动启动进度条动画# 启动加载线程self.loadingThread = LoadingThread()self.loadingThread.finished.connect(self.progressBar.stop)self.loadingThread.start()if __name__ == '__main__':import sysapp = QApplication(sys.argv)w = Window()w.show()sys.exit(app.exec_())

具体介绍

1. 导入必要模块

 
from PyQt5.QtCore import QSize, pyqtProperty, QTimer, Qt, QThread, pyqtSignal
from PyQt5.QtGui import QColor, QPainter
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QPushButton, QVBoxLayout, QLabel, QGridLayout

  • QSize: 控件的尺寸类。
  • pyqtProperty: 用于创建自定义的属性,使其可以与PyQt的信号和槽系统协作。
  • QTimer: 用于控制加载动画的定时器。
  • Qt: 包含常用的Qt标志和属性(例如布局方向、对齐方式等)。
  • QThreadpyqtSignal: 用于多线程处理,QThread允许后台执行任务,pyqtSignal用于在任务完成时发出信号。
  • QColorQPainter: 用于绘制和处理颜色的类。
  • QWidget 及其子类用于创建UI控件(例如按钮、布局、标签等)。

2. CircleProgressBar 类

 
class CircleProgressBar(QWidget):Color = QColor(37, 162, 208)  # 圆圈颜色Clockwise = True  # 是否顺时针旋转Delta = 36  # 每次旋转的角度增量

  • 该类定义了一个自定义的环形进度条,并继承自 QWidget
  • 主要负责绘制并控制环形加载动画。
初始化方法
 
def __init__(self, *args, color=None, clockwise=True, **kwargs):super(CircleProgressBar, self).__init__(*args, **kwargs)self.angle = 0  # 当前旋转的角度self.Clockwise = clockwise  # 控制旋转方向if color:self.Color = color  # 可以通过参数自定义进度条颜色self._timer = QTimer(self, timeout=self.update)  # 定时器用于定时更新动画

  • angle:控制动画的当前角度。
  • QTimer:每隔100ms触发一次,调用update()方法刷新绘制。
启动和停止动画的方法
def start(self):"""启动进度条的加载动画"""self._timer.start(100)def stop(self):"""停止进度条的加载动画并删除控件"""self._timer.stop()self.deleteLater()  # 删除控件以释放资源

  • start():启动定时器,进而启动动画。
  • stop():停止动画并销毁该进度条控件。
绘制环形动画
 
def paintEvent(self, event):super(CircleProgressBar, self).paintEvent(event)painter = QPainter(self)painter.setRenderHint(QPainter.Antialiasing)painter.translate(self.width() / 2, self.height() / 2)side = min(self.width(), self.height())painter.scale(side / 100.0, side / 100.0)painter.rotate(self.angle)painter.save()painter.setPen(Qt.NoPen)color = self.Color.toRgb()for i in range(11):color.setAlphaF(1.0 * i / 10)painter.setBrush(color)painter.drawEllipse(30, -10, 20, 20)painter.rotate(36)painter.restore()self.angle += self.Delta if self.Clockwise else -self.Deltaself.angle %= 360

  • paintEvent():负责绘制进度条的环形动画。
    • painter.translate():将画布的坐标系中心移动到控件的中心位置。
    • painter.scale():缩放画布,以适应控件的大小。
    • painter.rotate():旋转环形的每个小圆点。
    • color.setAlphaF():为每个圆点设置透明度,透明度从最低到最高,形成渐隐效果。
    • painter.drawEllipse():绘制每个小圆点。
    • 每次更新动画时,角度都会增加或减少,形成旋转效果。
自定义属性
  • 使用 pyqtProperty 定义了自定义的属性 color, clockwise, delta,使它们能够与PyQt的属性系统兼容。

3. LoadingThread 类

 
class LoadingThread(QThread):"""模拟加载过程的线程"""finished = pyqtSignal()def run(self):import timetime.sleep(5)  # 模拟加载时间self.finished.emit()  # 加载完成后发出信号

  • 该类继承自 QThread,用于模拟后台任务(这里通过 time.sleep(5) 模拟了5秒的加载过程)。
  • finished 信号用于通知主线程加载完成。
  • 主要用于模拟耗时任务,同时保持UI的响应性。

4. CustomWidget 类

 
class CustomWidget(QWidget):"""每个子控件,包含两个按钮"""def __init__(self, main_window, bg_color, *args, **kwargs):super(CustomWidget, self).__init__(*args, **kwargs)layout = QVBoxLayout(self)self.setStyleSheet(f"background-color: {bg_color};")self.centerLoadButton = QPushButton("主UI中居中加载")self.centerLoadButton.clicked.connect(self.startLoadingInMain)layout.addWidget(self.centerLoadButton)self.localLoadButton = QPushButton("本控件中加载")self.localLoadButton.clicked.connect(self.startLoadingInLocal)layout.addWidget(self.localLoadButton)

  • 这是自定义的控件,每个控件内部包含两个按钮:
    • centerLoadButton:触发主窗口的居中加载动画。
    • localLoadButton:在该控件内显示加载动画。
  • 每个控件的背景颜色由参数 bg_color 决定。

5. Window 类

 
class Window(QWidget):def __init__(self, *args, **kwargs):super(Window, self).__init__(*args, **kwargs)self.initUI()def initUI(self):layout = QGridLayout(self)self.setLayout(layout)# 创建四个子控件,并为每个控件指定不同的背景颜色widget1 = CustomWidget(self, "lightblue")widget2 = CustomWidget(self, "lightgreen")widget3 = CustomWidget(self, "lightcoral")widget4 = CustomWidget(self, "lightyellow")layout.addWidget(widget1, 0, 0)layout.addWidget(widget2, 0, 1)layout.addWidget(widget3, 1, 0)layout.addWidget(widget4, 1, 1)

  • Window 类是应用的主窗口,继承自 QWidget
  • 它使用了 QGridLayout 布局,将四个不同颜色的 CustomWidget 放置在窗口的不同位置。
在窗口中央显示加载动画
 
def startLoadingInCenter(self):"""在主窗口中心显示加载动画"""self.progressBar = CircleProgressBar(self)self.progressBar.setFixedSize(100, 100)self.progressBar.show()self.progressBar.move(self.width() // 2 - self.progressBar.width() // 2,self.height() // 2 - self.progressBar.height() // 2)self.progressBar.start()self.loadingThread = LoadingThread()self.loadingThread.finished.connect(self.progressBar.stop)self.loadingThread.start()

  • 该方法在主窗口中心显示环形进度条。
  • 创建进度条后,启动加载动画,并启动 LoadingThread 模拟加载任务。
  • 加载完成后,停止并删除进度条。
在子控件内显示加载动画
 
def startLoadingInWidget(self, widget):"""在指定的小部件内显示加载动画"""self.progressBar = CircleProgressBar(widget)self.progressBar.setFixedSize(50, 50)self.progressBar.show()self.progressBar.move(widget.width() // 2 - self.progressBar.width() // 2,widget.height() // 2 - self.progressBar.height() // 2)self.progressBar.start()self.loadingThread = LoadingThread()self.loadingThread.finished.connect(self.progressBar.stop)self.loadingThread.start()

  • 该方法在特定的子控件内显示环形进度条动画。

6. 主程序执行

 
if __name__ == '__main__':import sysapp = QApplication(sys.argv)w = Window()w.show()sys.exit(app.exec_())

  • 程序的入口,创建 QApplication 实例并启动事件循环。

总结

  • 该程序展示了如何创建一个带有环形加载动画的PyQt5应用程序。
  • CircleProgressBar 负责绘制并控制动画,LoadingThread 模拟后台任务。
  • 主窗口 Window 包含四个不同颜色的子控件,用户可以选择在主窗口或子控件内显示加载动画。

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

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

相关文章

数据与结构算法平衡二叉树详解叉树--基本概念

平衡二叉树(Balanced Binary Tree)又被称为AVL树(有别于AVL算法),且具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。这个方案很好…

图解Redis 01 | 初识Redis

什么是 Redis? Redis 是一种基于内存的数据库,所有的数据读写操作都在内存中完成,因此读写速度非常快。它被广泛应用于缓存、消息队列、分布式锁等场景。 Redis 提供了多种数据类型来支持不同的业务需求,如 String、Hash、List、…

环形数组与单向链表的队列实现(Queue)

什么是队列 队列是一种重要的线性数据结构,具有先进先出(FIFO)的特性。元素的插入操作称为入队,删除操作称为出队。队列在许多计算机科学应用中非常常见,如任务调度和数据缓冲等。 在实现队列时,可…

路由策略PBR

文章目录 策略路由PBR概述本地流量接口策略 策略路由 策略路由和路由策略的区别: 策略路由可以不按照路由表进行转发路由策略主要控制路由信息的引入、发布和接受等,主要靠 RIB和FIB PBR概述 比路由策略耗资源,直接跳过路由表,数…

Pytorch详解-模型模块(RNN,CNN,FNN,LSTM,GRU,TCN,Transformer)

Pytorch详解-模型模块 Module & parameterModule初认识forward函数 ParameterPytorch中的权重、参数和超参数 Module容器-ContainersSequentialModuleListModuleDictParameterList & ParameterDict 常用网络层LSTM输入和输出 GRUConvolutional Layers卷积层的基本概念常…

IP协议及相关特性

IP协议负责地址管理和路由选择。它的组成为: 接下来我们将对其中较重要的部分进行介绍。 4位版本:这里的四位版本只有两个取值 分别为IPv4和IPv6,这两个额分别为不同的IP协议,但是现在主流的还是IPv4但是近年来IPv6在中国的普及率…

linux系统如何通过进程PID号找到对应的程序在系统中的路径

linux系统如何通过进程PID号找到对应的程序在系统中的路径 首先我们用ps -aux​命令找到对应进程的PID号,比如我这里要得就是xmrig这个进程的PID号 ​​ 通过lsof命令查看对应进程的关联的文件,并找到可执行文件的路径 lsof -p 22785 | grep txt​​ 或…

棉花叶片病害检测数据集

【棉花叶片病害检测数据集】nc: 5 names: [blight, curl, healthy, wilt, wilt_png] 名称:【枯萎病, 卷叶病, 健康,萎蔫病,‘萎蔫病图像’】共3474张,8:1:1比例划分,(train;2888张,val&#xff…

MVCC机制解析:提升数据库并发性能的关键

MVCC机制解析:提升数据库并发性能的关键 MVCC(Multi-Version Concurrency Control) 多版本并发控制 。 MVCC只在事务隔离级别为读已提交(Read Committed)和可重复读(Repeated Read)下生效。 MVCC是做什么用的 MVCC是为了处理 可重复读 和…

C++ 带约束的Ceres形状拟合

C 带约束的Ceres形状拟合 一、Ceres Solver1.定义问题2. 添加残差AddResidualBlockAutoDiffCostFunction 3. 配置求解器4. 求解5. 检查结果 二、基于Ceres的最佳拟合残差结构体拟合主函数 三、带约束的Ceres拟合残差设计拟合区间限定 四、拟合结果bestminmax 五、完整代码 对Ce…

无法将ggplot图保存为PDF文件怎么办

即serif代表Times New Roman字体,sans代表Arial字体,mono代表Courier New字体。这种映射关系在基础绘图系统和ggplot2系统中均可使用。 既然字体找不到,那么就导入我们电脑的字体咯: # 这个代码只需运行一次 extrafont::font_im…

使用GitHub Actions实现前后端CI/CD到云服务器

一、静态站点部署(前端) 如果你要部署到github pages或者你不用SSR(服务端渲染),那就构建(SSG)静态站点 配置 nextjs配置SSG(静态站点)next.config.mjs,其…

跨域训练评估BEVal:自动驾驶 BEV 的跨数据集评估框架

跨域训练评估BEVal:自动驾驶 BEV 的跨数据集评估框架 Abstract 当前在自动驾驶中的鸟瞰图语义分割研究主要集中在使用单个数据集(通常是nuScenes数据集)优化神经网络模型。这种做法导致了高度专业化的模型,可能在面对不同环境或…

孙溟㠭浅析中国碑帖〈曹全碑〉

孙溟㠭浅析中国碑帖《曹全碑》 《曹全碑》 《曹全碑》亦称《郃阳令曹全碑》,东汉时期的碑刻。属于隶书体,东汉中平二年(公元158年)立碑。 《曹全碑》 于明代万历初年在陕西郃阳县莘里村被发现,碑文记载了东汉末年曹全…

2025秋招LLM大模型多模态面试题(七)- 思维链CoT

1.思维链(cot) 论文名称:Chain-of-Thought Prompting Elicits Reasoningin Large Language Models论文连接:Chain-of-Thought Prompting Elicits Reasoningin Large Language Models1.什么是思维链提示? 思维链(CoT)提示过程是一种最近开发的提示方法,它鼓励大语言模型解…

GUI编程14:Icon(图标)、ImageIcon(图像图标)标签

视频链接:16、Icon、ImageIcon标签_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1DJ411B75F?p16&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5 1.在Label上添加Icon package com.yundait.lesson04;import javax.swing.*; import java.awt.*;public cl…

C++数据结构-树的深度优先搜索及树形模拟法运用(进阶篇)

1. DFS简介 深度优先搜索算法(英语:Depth-First-Search,简称DFS)是一种用于遍历或搜索树或图的算法。 沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所在边都己被探寻过或者在搜寻时结点不满足条件&am…

Vue2电商平台项目 (三) Search模块、面包屑(页面自己跳自己)、排序、分页器!

文章目录 一、Search模块1、Search模块的api2、Vuex保存数据3、组件获取vuex数据并渲染(1)、分析请求数据的数据结构(2)、getters简化数据、渲染页面 4、Search模块根据不同的参数获取数据(1)、 派发actions的操作封装为函数(2)、设置带给服务器的参数(3)、Object.assign整理参…

comfyui中报错 Cmd(‘git‘) failed due to: exit code(128) 如何解决

🎈背景 comfyui今天在安装插件的过程中,发现有个插件第一次安装失败后,再次安装就开始报错了,提示: ComfyUI-Inpaint-CropAndStitch install failed: Bad Request 截图如下: 看下后台的报错: …

输入一个整数表示输出函数,也表示组成正方形边的*的数量

//输入一个整数表示输出函数&#xff0c;也表示组成正方形边的*的数量 //空心正方形 #include<stdio.h> int main() {int c 5;int i 0;int a[5][5] { 0 };int j 0;for (i 0; i < c; i){for (j 0; j < c; j){if (i 0)a[i][j] *;else if (j 0)a[i][j] *;el…