最近项目部署需要用到圆环进度条,在网上找了很多资料,发现没有一个是基于PyQt5实现的,大部分都是用PyQt5自带的或者是用C实现的,很明显,这是不符合需求的,所以不懂C的我硬着头皮看着C代码来实现PyQt5版本的圆环进度条。项目地址:RoundProgress。
代码如下:
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5 import *
class RoundProgress(QWidget):
def __init__(self):
super(RoundProgress, self).__init__()
self.setWindowFlags(Qt.FramelessWindowHint) # 去边框
self.setAttribute(Qt.WA_TranslucentBackground) # 设置窗口背景透明
self.persent = 0
self.my_thread = MyThread()
self.my_thread.my_signal.connect(self.parameterUpdate)
self.my_thread.start()
def parameterUpdate(self, p):
self.persent = p
def paintEvent(self, event):
rotateAngle = 360 * self.persent / 100
# 绘制准备工作,启用反锯齿
painter = QPainter(self)
painter.setRenderHints(QtGui.QPainter.Antialiasing)
painter.setPen(QtCore.Qt.NoPen)
painter.setBrush(QBrush(QColor("#5F89FF")))
painter.drawEllipse(3, 3, 100, 100) # 画外圆
painter.setBrush(QBrush(QColor("#e3ebff")))
painter.drawEllipse(5, 5, 96, 96) # 画内圆
gradient = QConicalGradient(50, 50, 91)
gradient.setColorAt(0, QColor("#95BBFF"))
gradient.setColorAt(1, QColor("#5C86FF"))
self.pen = QPen()
self.pen.setBrush(gradient) # 设置画刷渐变效果
self.pen.setWidth(8)
self.pen.setCapStyle(Qt.RoundCap)
painter.setPen(self.pen)
painter.drawArc(QtCore.QRectF(4, 4, 98, 98), (90 - 0) * 16, -rotateAngle * 16) # 画圆环
font = QtGui.QFont()
font.setFamily("微软雅黑")
font.setPointSize(11)
painter.setFont(font)
painter.setPen(QColor("#5481FF"))
painter.drawText(QtCore.QRectF(4, 4, 98, 98), Qt.AlignCenter, "%d%%" % self.persent) # 显示进度条当前进度
self.update()
class MyThread(QThread):
my_signal = pyqtSignal(int)
p = 0
def __init__(self):
super(MyThread, self).__init__()
def run(self):
while self.p < 100:
self.p += 1
self.my_signal.emit(self.p)
self.msleep(100)
if __name__ == '__main__':
app = QApplication(sys.argv)
RoundProgress = RoundProgress()
RoundProgress.show()
sys.exit(app.exec_())
通过QPainter画出进度条,再利用QThread实时更新参数 ,效果如下:
self.setWindowFlags(Qt.FramelessWindowHint) # 去边框
self.setAttribute(Qt.WA_TranslucentBackground) # 设置窗口背景透明
这两行代码可以去掉Qt自带的框,只显示绘画的内容。(第一行还可以用来重新制作标题栏)
painter = QPainter(self)
painter.setRenderHints(QtGui.QPainter.Antialiasing)
设置QPainter画出圆滑效果。
painter.setPen(QtCore.Qt.NoPen)
painter.setBrush(QBrush(QColor("#5F89FF")))
painter.drawEllipse(3, 3, 100, 100) # 画外圆
画笔是用来画边的,所以这里就不设置画笔了,设置画刷的颜色为深蓝色,painter.drawEllipse(3, 3, 100, 100)这句代码的前两个参数是圆的坐标,后两个参数是图的宽高,当宽高一样时,画出来的效果就是深蓝色的圆,以此类推,先画大的外圆再画小的内圆(内圆相当于遮罩)
painter.drawArc(QtCore.QRectF(4, 4, 98, 98), (90 - 0) * 16, -rotateAngle * 16) # 画圆环
画圆弧第一个参数是和画圆的参数是一样的,包含四个参数,第二个参数为起始角度(3点钟为初始角度0度,逆时针为正,乘16,因为单位为alen,一度=16alen),第三个参数为结束角度
class MyThread(QThread):
my_signal = pyqtSignal(int)
p = 0
def __init__(self):
super(MyThread, self).__init__()
def run(self):
while self.p < 100:
self.p += 1
self.my_signal.emit(self.p)
self.msleep(100)
- 这个类是多线程类,可以用来实时更新参数,为了演示一下这里我把p的值写了个循环,每次加1,实际上传参的时候p是要作为全局变量才能更新,所以我把p的值定义在函数外,注意更新参数的时候一定要调用这个类的全局变量,而不是重新实例化传参,这样地址才能传对。
- 下面的run函数要用循环才能不断调用线程。pyqtSignal(int)加上int就代表这个信号可以传一个int数值,然后在run()函数中,调用信号的emit()函数释放信号。也就是说每次循环都会释放信号,而该信号会同时传递self.p变量的int数值。
self.my_thread = MyThread()
self.my_thread.my_signal.connect(self.parameterUpdate)
self.my_thread.start()
调用线程,进行信号和槽的连接,在槽函数中我们将self.persent的值设为传递过来的数值,然后启动线程。
如果要把进度条画在部件上,可以参考以下链接和代码:
self.stack = QStackedWidget()
self.paint = RoundProgress()
self.stack.addWidget(self.paint)
self.horizontalLayout.addWidget(self.stack)
绘画和多线程参考链接:
https://www.jianshu.com/p/ab7853800d60