Files
fluent_widgets_pyside6/qfluentwidgets/components/widgets/progress_ring.py
2025-08-14 18:45:16 +08:00

212 lines
6.7 KiB
Python

# coding:utf-8
from PySide6.QtCore import (Qt, QRectF, QEasingCurve, QPropertyAnimation, QParallelAnimationGroup,
QSequentialAnimationGroup, Property)
from PySide6.QtGui import QColor, QPen, QPainter, QFont
from PySide6.QtWidgets import QProgressBar
from .progress_bar import ProgressBar
from ...common.font import setFont
from ...common.style_sheet import themeColor, isDarkTheme
class ProgressRing(ProgressBar):
""" Progress ring """
def __init__(self, parent=None, useAni=True):
super().__init__(parent, useAni=useAni)
self.lightBackgroundColor = QColor(0, 0, 0, 34)
self.darkBackgroundColor = QColor(255, 255, 255, 34)
self._strokeWidth = 6
self.setTextVisible(False)
self.setFixedSize(100, 100)
setFont(self)
def getStrokeWidth(self):
return self._strokeWidth
def setStrokeWidth(self, w: int):
self._strokeWidth = w
self.update()
def _drawText(self, painter: QPainter, text: str):
""" draw text """
painter.setFont(self.font())
painter.setPen(Qt.white if isDarkTheme() else Qt.black)
painter.drawText(self.rect(), Qt.AlignCenter, text)
def paintEvent(self, e):
painter = QPainter(self)
painter.setRenderHints(QPainter.Antialiasing)
cw = self._strokeWidth # circle thickness
w = min(self.height(), self.width()) - cw
rc = QRectF(cw/2, self.height()/2 - w/2, w, w)
# draw background
bc = self.darkBackgroundColor if isDarkTheme() else self.lightBackgroundColor
pen = QPen(bc, cw, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
painter.setPen(pen)
painter.drawArc(rc, 0, 360*16)
if self.maximum() <= self.minimum():
return
# draw bar
pen.setColor(self.barColor())
painter.setPen(pen)
degree = int(self.val / (self.maximum() - self.minimum()) * 360)
painter.drawArc(rc, 90*16, -degree*16)
# draw text
if self.isTextVisible():
self._drawText(painter, self.valText())
strokeWidth = Property(int, getStrokeWidth, setStrokeWidth)
class IndeterminateProgressRing(QProgressBar):
""" Indeterminate progress ring """
def __init__(self, parent=None, start=True):
super().__init__(parent=parent)
self.lightBackgroundColor = QColor(0, 0, 0, 0)
self.darkBackgroundColor = QColor(255, 255, 255, 0)
self._lightBarColor = QColor()
self._darkBarColor = QColor()
self._strokeWidth = 6
self._startAngle = -180
self._spanAngle = 0
self.startAngleAni1 = QPropertyAnimation(self, b'startAngle', self)
self.startAngleAni2 = QPropertyAnimation(self, b'startAngle', self)
self.spanAngleAni1 = QPropertyAnimation(self, b'spanAngle', self)
self.spanAngleAni2 = QPropertyAnimation(self, b'spanAngle', self)
self.startAngleAniGroup = QSequentialAnimationGroup(self)
self.spanAngleAniGroup = QSequentialAnimationGroup(self)
self.aniGroup = QParallelAnimationGroup(self)
# initialize start angle animation
self.startAngleAni1.setDuration(1000)
self.startAngleAni1.setStartValue(0)
self.startAngleAni1.setEndValue(450)
self.startAngleAni2.setDuration(1000)
self.startAngleAni2.setStartValue(450)
self.startAngleAni2.setEndValue(1080)
self.startAngleAniGroup.addAnimation(self.startAngleAni1)
self.startAngleAniGroup.addAnimation(self.startAngleAni2)
# initialize span angle animation
self.spanAngleAni1.setDuration(1000)
self.spanAngleAni1.setStartValue(0)
self.spanAngleAni1.setEndValue(180)
self.spanAngleAni2.setDuration(1000)
self.spanAngleAni2.setStartValue(180)
self.spanAngleAni2.setEndValue(0)
self.spanAngleAniGroup.addAnimation(self.spanAngleAni1)
self.spanAngleAniGroup.addAnimation(self.spanAngleAni2)
self.aniGroup.addAnimation(self.startAngleAniGroup)
self.aniGroup.addAnimation(self.spanAngleAniGroup)
self.aniGroup.setLoopCount(-1)
self.setFixedSize(80, 80)
if start:
self.start()
@Property(int)
def startAngle(self):
return self._startAngle
@startAngle.setter
def startAngle(self, angle: int):
self._startAngle = angle
self.update()
@Property(int)
def spanAngle(self):
return self._spanAngle
@spanAngle.setter
def spanAngle(self, angle: int):
self._spanAngle = angle
self.update()
def getStrokeWidth(self):
return self._strokeWidth
def setStrokeWidth(self, w: int):
self._strokeWidth = w
self.update()
def start(self):
""" start spin """
self._startAngle = 0
self._spanAngle = 0
self.aniGroup.start()
def stop(self):
""" stop spin """
self.aniGroup.stop()
self.startAngle = 0
self.spanAngle = 0
def lightBarColor(self):
return self._lightBarColor if self._lightBarColor.isValid() else themeColor()
def darkBarColor(self):
return self._darkBarColor if self._darkBarColor.isValid() else themeColor()
def setCustomBarColor(self, light, dark):
""" set the custom bar color
Parameters
----------
light, dark: str | Qt.GlobalColor | QColor
bar color in light/dark theme mode
"""
self._lightBarColor = QColor(light)
self._darkBarColor = QColor(dark)
self.update()
def setCustomBackgroundColor(self, light, dark):
""" set the custom background color
Parameters
----------
light, dark: str | Qt.GlobalColor | QColor
background color in light/dark theme mode
"""
self.lightBackgroundColor = QColor(light)
self.darkBackgroundColor = QColor(dark)
self.update()
def paintEvent(self, e):
painter = QPainter(self)
painter.setRenderHints(QPainter.Antialiasing)
cw = self._strokeWidth
w = min(self.height(), self.width()) - cw
rc = QRectF(cw/2, self.height()/2 - w/2, w, w)
# draw background
bc = self.darkBackgroundColor if isDarkTheme() else self.lightBackgroundColor
pen = QPen(bc, cw, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
painter.setPen(pen)
painter.drawArc(rc, 0, 360*16)
# draw bar
pen.setColor(self.darkBarColor() if isDarkTheme() else self.lightBarColor())
painter.setPen(pen)
startAngle = -self.startAngle + 180
painter.drawArc(rc, (startAngle % 360)*16, -self.spanAngle*16)
strokeWidth = Property(int, getStrokeWidth, setStrokeWidth)