2018-09-04 15:10:24 +08:00
|
|
|
#!/usr/bin/env python
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
"""
|
|
|
|
Created on 2018年9月4日
|
|
|
|
@author: Irony
|
2018-12-28 23:09:46 +08:00
|
|
|
@site: https://pyqt5.com , https://github.com/892768447
|
2018-09-04 15:10:24 +08:00
|
|
|
@email: 892768447@qq.com
|
2018-12-31 14:49:29 +08:00
|
|
|
@file: PercentProgressBar
|
2018-09-04 15:10:24 +08:00
|
|
|
@description:
|
|
|
|
"""
|
|
|
|
from PyQt5.QtCore import pyqtProperty, QSize, Qt, QRectF, QTimer
|
|
|
|
from PyQt5.QtGui import QColor, QPainter, QFont
|
|
|
|
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QSlider
|
|
|
|
|
|
|
|
|
|
|
|
__Author__ = """By: Irony
|
|
|
|
QQ: 892768447
|
|
|
|
Email: 892768447@qq.com"""
|
|
|
|
__Copyright__ = "Copyright (c) 2018 Irony"
|
|
|
|
__Version__ = "Version 1.0"
|
|
|
|
|
|
|
|
|
|
|
|
class PercentProgressBar(QWidget):
|
|
|
|
|
|
|
|
MinValue = 0
|
|
|
|
MaxValue = 100
|
|
|
|
Value = 0
|
|
|
|
BorderWidth = 8
|
|
|
|
Clockwise = True # 顺时针还是逆时针
|
|
|
|
ShowPercent = True # 是否显示百分比
|
|
|
|
ShowFreeArea = False # 显示背后剩余
|
|
|
|
ShowSmallCircle = False # 显示带头的小圆圈
|
|
|
|
TextColor = QColor(255, 255, 255) # 文字颜色
|
|
|
|
BorderColor = QColor(24, 189, 155) # 边框圆圈颜色
|
|
|
|
BackgroundColor = QColor(70, 70, 70) # 背景颜色
|
|
|
|
|
|
|
|
def __init__(self, *args, value=0, minValue=0, maxValue=100,
|
|
|
|
borderWidth=8, clockwise=True, showPercent=True,
|
|
|
|
showFreeArea=False, showSmallCircle=False,
|
|
|
|
textColor=QColor(255, 255, 255),
|
|
|
|
borderColor=QColor(24, 189, 155),
|
|
|
|
backgroundColor=QColor(70, 70, 70), **kwargs):
|
|
|
|
super(PercentProgressBar, self).__init__(*args, **kwargs)
|
|
|
|
self.Value = value
|
|
|
|
self.MinValue = minValue
|
|
|
|
self.MaxValue = maxValue
|
|
|
|
self.BorderWidth = borderWidth
|
|
|
|
self.Clockwise = clockwise
|
|
|
|
self.ShowPercent = showPercent
|
|
|
|
self.ShowFreeArea = showFreeArea
|
|
|
|
self.ShowSmallCircle = showSmallCircle
|
|
|
|
self.TextColor = textColor
|
|
|
|
self.BorderColor = borderColor
|
|
|
|
self.BackgroundColor = backgroundColor
|
|
|
|
|
|
|
|
def setRange(self, minValue: int, maxValue: int):
|
|
|
|
if minValue >= maxValue: # 最小值>=最大值
|
|
|
|
return
|
|
|
|
self.MinValue = minValue
|
|
|
|
self.MaxValue = maxValue
|
|
|
|
self.update()
|
|
|
|
|
|
|
|
def paintEvent(self, event):
|
|
|
|
super(PercentProgressBar, self).paintEvent(event)
|
|
|
|
width = self.width()
|
|
|
|
height = self.height()
|
|
|
|
side = min(width, height)
|
|
|
|
|
|
|
|
painter = QPainter(self)
|
|
|
|
# 反锯齿
|
|
|
|
painter.setRenderHints(QPainter.Antialiasing |
|
|
|
|
QPainter.TextAntialiasing)
|
|
|
|
# 坐标中心为中间点
|
|
|
|
painter.translate(width / 2, height / 2)
|
|
|
|
# 按照100x100缩放
|
|
|
|
painter.scale(side / 100.0, side / 100.0)
|
|
|
|
|
|
|
|
# 绘制中心园
|
|
|
|
self._drawCircle(painter, 50)
|
|
|
|
# 绘制圆弧
|
|
|
|
self._drawArc(painter, 50 - self.BorderWidth / 2)
|
|
|
|
# 绘制文字
|
|
|
|
self._drawText(painter, 50)
|
|
|
|
|
|
|
|
def _drawCircle(self, painter: QPainter, radius: int):
|
|
|
|
# 绘制中心园
|
|
|
|
radius = radius - self.BorderWidth
|
|
|
|
painter.save()
|
|
|
|
painter.setPen(Qt.NoPen)
|
|
|
|
painter.setBrush(self.BackgroundColor)
|
|
|
|
painter.drawEllipse(QRectF(-radius, -radius, radius * 2, radius * 2))
|
|
|
|
painter.restore()
|
|
|
|
|
|
|
|
def _drawArc(self, painter: QPainter, radius: int):
|
|
|
|
# 绘制圆弧
|
|
|
|
painter.save()
|
|
|
|
painter.setBrush(Qt.NoBrush)
|
|
|
|
# 修改画笔
|
|
|
|
pen = painter.pen()
|
|
|
|
pen.setWidthF(self.BorderWidth)
|
|
|
|
pen.setCapStyle(Qt.RoundCap)
|
|
|
|
|
|
|
|
arcLength = 360.0 / (self.MaxValue - self.MinValue) * self.Value
|
|
|
|
rect = QRectF(-radius, -radius, radius * 2, radius * 2)
|
|
|
|
|
|
|
|
if not self.Clockwise:
|
|
|
|
# 逆时针
|
|
|
|
arcLength = -arcLength
|
|
|
|
|
|
|
|
# 绘制剩余进度圆弧
|
|
|
|
if self.ShowFreeArea:
|
|
|
|
acolor = self.BorderColor.toRgb()
|
|
|
|
acolor.setAlphaF(0.2)
|
|
|
|
pen.setColor(acolor)
|
|
|
|
painter.setPen(pen)
|
|
|
|
painter.drawArc(rect, (0 - arcLength) *
|
|
|
|
16, -(360 - arcLength) * 16)
|
|
|
|
|
|
|
|
# 绘制当前进度圆弧
|
|
|
|
pen.setColor(self.BorderColor)
|
|
|
|
painter.setPen(pen)
|
|
|
|
painter.drawArc(rect, 0, -arcLength * 16)
|
|
|
|
|
|
|
|
# 绘制进度圆弧前面的小圆
|
|
|
|
if self.ShowSmallCircle:
|
|
|
|
offset = radius - self.BorderWidth + 1
|
|
|
|
radius = self.BorderWidth / 2 - 1
|
|
|
|
painter.rotate(-90)
|
|
|
|
circleRect = QRectF(-radius, radius + offset,
|
|
|
|
radius * 2, radius * 2)
|
|
|
|
painter.rotate(arcLength)
|
|
|
|
painter.drawEllipse(circleRect)
|
|
|
|
|
|
|
|
painter.restore()
|
|
|
|
|
|
|
|
def _drawText(self, painter: QPainter, radius: int):
|
|
|
|
# 绘制文字
|
|
|
|
painter.save()
|
|
|
|
painter.setPen(self.TextColor)
|
|
|
|
painter.setFont(QFont('Arial', 25))
|
|
|
|
strValue = '{}%'.format(int(self.Value / (self.MaxValue - self.MinValue)
|
|
|
|
* 100)) if self.ShowPercent else str(self.Value)
|
|
|
|
painter.drawText(QRectF(-radius, -radius, radius * 2,
|
|
|
|
radius * 2), Qt.AlignCenter, strValue)
|
|
|
|
painter.restore()
|
|
|
|
|
|
|
|
@pyqtProperty(int)
|
|
|
|
def minValue(self) -> int:
|
|
|
|
return self.MinValue
|
|
|
|
|
|
|
|
@minValue.setter
|
|
|
|
def minValue(self, minValue: int):
|
|
|
|
if self.MinValue != minValue:
|
|
|
|
self.MinValue = minValue
|
|
|
|
self.update()
|
|
|
|
|
|
|
|
@pyqtProperty(int)
|
|
|
|
def maxValue(self) -> int:
|
|
|
|
return self.MaxValue
|
|
|
|
|
|
|
|
@maxValue.setter
|
|
|
|
def maxValue(self, maxValue: int):
|
|
|
|
if self.MaxValue != maxValue:
|
|
|
|
self.MaxValue = maxValue
|
|
|
|
self.update()
|
|
|
|
|
|
|
|
@pyqtProperty(int)
|
|
|
|
def value(self) -> int:
|
|
|
|
return self.Value
|
|
|
|
|
|
|
|
@value.setter
|
|
|
|
def value(self, value: int):
|
|
|
|
if self.Value != value:
|
|
|
|
self.Value = value
|
|
|
|
self.update()
|
|
|
|
|
|
|
|
@pyqtProperty(float)
|
|
|
|
def borderWidth(self) -> float:
|
|
|
|
return self.BorderWidth
|
|
|
|
|
|
|
|
@borderWidth.setter
|
|
|
|
def borderWidth(self, borderWidth: float):
|
|
|
|
if self.BorderWidth != borderWidth:
|
|
|
|
self.BorderWidth = borderWidth
|
|
|
|
self.update()
|
|
|
|
|
|
|
|
@pyqtProperty(bool)
|
|
|
|
def clockwise(self) -> bool:
|
|
|
|
return self.Clockwise
|
|
|
|
|
|
|
|
@clockwise.setter
|
|
|
|
def clockwise(self, clockwise: bool):
|
|
|
|
if self.Clockwise != clockwise:
|
|
|
|
self.Clockwise = clockwise
|
|
|
|
self.update()
|
|
|
|
|
|
|
|
@pyqtProperty(bool)
|
|
|
|
def showPercent(self) -> bool:
|
|
|
|
return self.ShowPercent
|
|
|
|
|
|
|
|
@showPercent.setter
|
|
|
|
def showPercent(self, showPercent: bool):
|
|
|
|
if self.ShowPercent != showPercent:
|
|
|
|
self.ShowPercent = showPercent
|
|
|
|
self.update()
|
|
|
|
|
|
|
|
@pyqtProperty(bool)
|
|
|
|
def showFreeArea(self) -> bool:
|
|
|
|
return self.ShowFreeArea
|
|
|
|
|
|
|
|
@showFreeArea.setter
|
|
|
|
def showFreeArea(self, showFreeArea: bool):
|
|
|
|
if self.ShowFreeArea != showFreeArea:
|
|
|
|
self.ShowFreeArea = showFreeArea
|
|
|
|
self.update()
|
|
|
|
|
|
|
|
@pyqtProperty(bool)
|
|
|
|
def showSmallCircle(self) -> bool:
|
|
|
|
return self.ShowSmallCircle
|
|
|
|
|
|
|
|
@showSmallCircle.setter
|
|
|
|
def showSmallCircle(self, showSmallCircle: bool):
|
|
|
|
if self.ShowSmallCircle != showSmallCircle:
|
|
|
|
self.ShowSmallCircle = showSmallCircle
|
|
|
|
self.update()
|
|
|
|
|
|
|
|
@pyqtProperty(QColor)
|
|
|
|
def textColor(self) -> QColor:
|
|
|
|
return self.TextColor
|
|
|
|
|
|
|
|
@textColor.setter
|
|
|
|
def textColor(self, textColor: QColor):
|
|
|
|
if self.TextColor != textColor:
|
|
|
|
self.TextColor = textColor
|
|
|
|
self.update()
|
|
|
|
|
|
|
|
@pyqtProperty(QColor)
|
|
|
|
def borderColor(self) -> QColor:
|
|
|
|
return self.BorderColor
|
|
|
|
|
|
|
|
@borderColor.setter
|
|
|
|
def borderColor(self, borderColor: QColor):
|
|
|
|
if self.BorderColor != borderColor:
|
|
|
|
self.BorderColor = borderColor
|
|
|
|
self.update()
|
|
|
|
|
|
|
|
@pyqtProperty(QColor)
|
|
|
|
def backgroundColor(self) -> QColor:
|
|
|
|
return self.BackgroundColor
|
|
|
|
|
|
|
|
@backgroundColor.setter
|
|
|
|
def backgroundColor(self, backgroundColor: QColor):
|
|
|
|
if self.BackgroundColor != backgroundColor:
|
|
|
|
self.BackgroundColor = backgroundColor
|
|
|
|
self.update()
|
|
|
|
|
|
|
|
def setValue(self, value):
|
|
|
|
self.value = value
|
|
|
|
|
|
|
|
def sizeHint(self) -> QSize:
|
|
|
|
return QSize(100, 100)
|
|
|
|
|
|
|
|
|
|
|
|
class Window(QWidget):
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
super(Window, self).__init__(*args, **kwargs)
|
|
|
|
layout = QHBoxLayout(self)
|
|
|
|
self._value = 0
|
|
|
|
self._widgets = []
|
|
|
|
self._timer = QTimer(self, timeout=self.updateValue)
|
|
|
|
|
|
|
|
self._widgets.append(PercentProgressBar(self))
|
|
|
|
layout.addWidget(self._widgets[0])
|
|
|
|
|
|
|
|
self._widgets.append(PercentProgressBar(self, clockwise=False))
|
|
|
|
layout.addWidget(self._widgets[1])
|
|
|
|
|
|
|
|
self._widgets.append(PercentProgressBar(self, showPercent=False))
|
|
|
|
layout.addWidget(self._widgets[2])
|
|
|
|
|
|
|
|
self._widgets.append(PercentProgressBar(self, showFreeArea=True))
|
|
|
|
layout.addWidget(self._widgets[3])
|
|
|
|
|
|
|
|
self._widgets.append(PercentProgressBar(self, showSmallCircle=True))
|
|
|
|
layout.addWidget(self._widgets[4])
|
|
|
|
|
|
|
|
self._widgets.append(PercentProgressBar(self, styleSheet="""
|
|
|
|
qproperty-textColor: rgb(255, 0, 0);
|
|
|
|
qproperty-borderColor: rgb(0, 255, 0);
|
|
|
|
qproperty-backgroundColor: rgb(0, 0, 255);
|
|
|
|
"""))
|
|
|
|
layout.addWidget(self._widgets[5])
|
|
|
|
|
|
|
|
rWidget = QWidget(self)
|
|
|
|
layout.addWidget(rWidget)
|
|
|
|
vlayout = QVBoxLayout(rWidget)
|
|
|
|
self.staticPercentProgressBar = PercentProgressBar(self)
|
|
|
|
self.staticPercentProgressBar.showFreeArea = True
|
|
|
|
self.staticPercentProgressBar.ShowSmallCircle = True
|
|
|
|
vlayout.addWidget(self.staticPercentProgressBar)
|
|
|
|
vlayout.addWidget(QSlider(self, minimum=0, maximum=100, orientation=Qt.Horizontal,
|
|
|
|
valueChanged=self.staticPercentProgressBar.setValue))
|
|
|
|
|
|
|
|
self._timer.start(100)
|
|
|
|
|
|
|
|
def updateValue(self):
|
|
|
|
for w in self._widgets:
|
|
|
|
w.value = self._value
|
|
|
|
self._value += 1
|
|
|
|
if self._value > 100:
|
|
|
|
self._value = 0
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
import sys
|
|
|
|
import cgitb
|
|
|
|
sys.excepthook = cgitb.Hook(1, None, 5, sys.stderr, 'text')
|
|
|
|
from PyQt5.QtWidgets import QApplication
|
|
|
|
app = QApplication(sys.argv)
|
|
|
|
w = Window()
|
|
|
|
w.show()
|
|
|
|
sys.exit(app.exec_())
|