2018-09-25 23:20:03 +08:00
|
|
|
|
#!/usr/bin/env python
|
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
|
|
# Created on 2018年4月1日
|
|
|
|
|
# author: Irony
|
2018-12-28 23:09:46 +08:00
|
|
|
|
# site: https://pyqt5.com , https://github.com/892768447
|
2018-09-25 23:20:03 +08:00
|
|
|
|
# email: 892768447@qq.com
|
2018-12-31 14:49:29 +08:00
|
|
|
|
# file: WaterRippleProgressBar
|
2018-09-25 23:20:03 +08:00
|
|
|
|
# description:
|
|
|
|
|
|
|
|
|
|
__Author__ = """By: Irony
|
|
|
|
|
QQ: 892768447
|
|
|
|
|
Email: 892768447@qq.com"""
|
|
|
|
|
__Copyright__ = 'Copyright (c) 2018 Irony'
|
|
|
|
|
__Version__ = 1.0
|
|
|
|
|
|
|
|
|
|
import math
|
|
|
|
|
|
|
|
|
|
from PyQt5.QtCore import QTimer, Qt, QRectF, QSize
|
|
|
|
|
from PyQt5.QtGui import QPainter, QPainterPath, QColor, QFont
|
|
|
|
|
from PyQt5.QtWidgets import QProgressBar
|
|
|
|
|
|
|
|
|
|
|
2018-12-31 14:49:29 +08:00
|
|
|
|
class WaterRippleProgressBar(QProgressBar):
|
2018-09-25 23:20:03 +08:00
|
|
|
|
|
|
|
|
|
# 浪高百分比
|
|
|
|
|
waterHeight = 1
|
|
|
|
|
# 密度
|
|
|
|
|
waterDensity = 1
|
|
|
|
|
# 样式1为矩形, 0为圆形
|
|
|
|
|
styleType = 1
|
|
|
|
|
# 文字颜色
|
|
|
|
|
textColor = Qt.white
|
|
|
|
|
# 背景颜色
|
|
|
|
|
backgroundColor = Qt.gray
|
|
|
|
|
# 波浪颜色1
|
|
|
|
|
waterColor1 = QColor(33, 178, 148)
|
|
|
|
|
# 波浪颜色2
|
|
|
|
|
waterColor2 = QColor(33, 178, 148, 100)
|
|
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
2018-12-31 14:49:29 +08:00
|
|
|
|
super(WaterRippleProgressBar, self).__init__(*args, **kwargs)
|
2018-09-25 23:20:03 +08:00
|
|
|
|
self._offset = 0
|
|
|
|
|
# 每隔100ms刷新波浪(模拟波浪动态)
|
|
|
|
|
self._updateTimer = QTimer(self, timeout=self.update)
|
|
|
|
|
self._updateTimer.start(100)
|
|
|
|
|
|
|
|
|
|
def setRange(self, minValue, maxValue):
|
|
|
|
|
if minValue == maxValue == 0:
|
|
|
|
|
return # 不允许设置busy状态
|
2018-12-31 14:49:29 +08:00
|
|
|
|
super(WaterRippleProgressBar, self).setRange(minValue, maxValue)
|
2018-09-25 23:20:03 +08:00
|
|
|
|
|
|
|
|
|
def setMinimum(self, value):
|
|
|
|
|
if value == self.maximum() == 0:
|
|
|
|
|
return # 不允许设置busy状态
|
2018-12-31 14:49:29 +08:00
|
|
|
|
super(WaterRippleProgressBar, self).setMinimum(value)
|
2018-09-25 23:20:03 +08:00
|
|
|
|
|
|
|
|
|
def setMaximum(self, value):
|
|
|
|
|
if value == self.minimum() == 0:
|
|
|
|
|
return # 不允许设置busy状态
|
2018-12-31 14:49:29 +08:00
|
|
|
|
super(WaterRippleProgressBar, self).setMaximum(value)
|
2018-09-25 23:20:03 +08:00
|
|
|
|
|
|
|
|
|
def setWaterHeight(self, height):
|
|
|
|
|
"""设置浪高"""
|
|
|
|
|
self.waterHeight = height
|
|
|
|
|
self.update()
|
|
|
|
|
|
|
|
|
|
def setWaterDensity(self, density):
|
|
|
|
|
"""设置密度"""
|
|
|
|
|
self.waterDensity = density
|
|
|
|
|
self.update()
|
|
|
|
|
|
|
|
|
|
def setStyleType(self, style):
|
|
|
|
|
"""设置类型"""
|
|
|
|
|
self.styleType = style
|
|
|
|
|
self.update()
|
|
|
|
|
|
|
|
|
|
def sizeHint(self):
|
|
|
|
|
return QSize(100, 100)
|
|
|
|
|
|
|
|
|
|
def paintEvent(self, event):
|
|
|
|
|
if self.minimum() == self.maximum() == 0:
|
|
|
|
|
return
|
|
|
|
|
# 正弦曲线公式 y = A * sin(ωx + φ) + k
|
|
|
|
|
# 当前值所占百分比
|
|
|
|
|
percent = 1 - (self.value() - self.minimum()) / \
|
|
|
|
|
(self.maximum() - self.minimum())
|
|
|
|
|
# w表示周期,6为人为定义
|
|
|
|
|
w = 6 * self.waterDensity * math.pi / self.width()
|
|
|
|
|
# A振幅 高度百分比,1/26为人为定义
|
|
|
|
|
A = self.height() * self.waterHeight * 1 / 26
|
|
|
|
|
# k 高度百分比
|
|
|
|
|
k = self.height() * percent
|
|
|
|
|
|
|
|
|
|
# 波浪1
|
|
|
|
|
waterPath1 = QPainterPath()
|
|
|
|
|
waterPath1.moveTo(0, self.height()) # 起点在左下角
|
|
|
|
|
# 波浪2
|
|
|
|
|
waterPath2 = QPainterPath()
|
|
|
|
|
waterPath2.moveTo(0, self.height()) # 起点在左下角
|
|
|
|
|
|
|
|
|
|
# 偏移
|
|
|
|
|
self._offset += 0.6
|
|
|
|
|
if self._offset > self.width() / 2:
|
|
|
|
|
self._offset = 0
|
|
|
|
|
|
|
|
|
|
for i in range(self.width() + 1):
|
|
|
|
|
# 从x轴开始计算y轴点
|
|
|
|
|
y = A * math.sin(w * i + self._offset) + k
|
|
|
|
|
waterPath1.lineTo(i, y)
|
|
|
|
|
|
|
|
|
|
# 相对第一条需要进行错位
|
|
|
|
|
y = A * math.sin(w * i + self._offset + self.width() / 2 * A) + k
|
|
|
|
|
waterPath2.lineTo(i, y)
|
|
|
|
|
|
|
|
|
|
# 封闭两条波浪,形成一个 U形 上面加波浪的封闭区间
|
|
|
|
|
waterPath1.lineTo(self.width(), self.height())
|
|
|
|
|
waterPath1.lineTo(0, self.height())
|
|
|
|
|
waterPath2.lineTo(self.width(), self.height())
|
|
|
|
|
waterPath2.lineTo(0, self.height())
|
|
|
|
|
|
|
|
|
|
# 整体形状(矩形或者圆形)
|
|
|
|
|
bgPath = QPainterPath()
|
|
|
|
|
if self.styleType:
|
|
|
|
|
bgPath.addRect(QRectF(self.rect()))
|
|
|
|
|
else:
|
|
|
|
|
radius = min(self.width(), self.height())
|
|
|
|
|
bgPath.addRoundedRect(QRectF(self.rect()), radius, radius)
|
|
|
|
|
|
|
|
|
|
# 开始画路径
|
|
|
|
|
painter = QPainter(self)
|
|
|
|
|
painter.setRenderHint(QPainter.Antialiasing, True)
|
|
|
|
|
# 设置没有画笔
|
|
|
|
|
painter.setPen(Qt.NoPen)
|
|
|
|
|
|
2018-12-31 14:49:29 +08:00
|
|
|
|
if not self.styleType:
|
|
|
|
|
# 圆形
|
|
|
|
|
painter.setClipPath(bgPath)
|
|
|
|
|
|
2018-09-25 23:20:03 +08:00
|
|
|
|
# 先整体绘制背景,然后再在背景上方绘制两条波浪
|
|
|
|
|
painter.save()
|
|
|
|
|
painter.setBrush(self.backgroundColor)
|
|
|
|
|
painter.drawPath(bgPath)
|
|
|
|
|
painter.restore()
|
|
|
|
|
|
|
|
|
|
# 波浪1
|
|
|
|
|
painter.save()
|
|
|
|
|
painter.setBrush(self.waterColor1)
|
|
|
|
|
painter.drawPath(waterPath1)
|
|
|
|
|
painter.restore()
|
|
|
|
|
|
|
|
|
|
# 波浪2
|
|
|
|
|
painter.save()
|
|
|
|
|
painter.setBrush(self.waterColor2)
|
|
|
|
|
painter.drawPath(waterPath2)
|
|
|
|
|
painter.restore()
|
|
|
|
|
|
|
|
|
|
# 绘制文字
|
|
|
|
|
if not self.isTextVisible():
|
|
|
|
|
return
|
|
|
|
|
painter.setPen(self.textColor)
|
|
|
|
|
font = self.font() or QFont()
|
|
|
|
|
font.setPixelSize(int(min(self.width(), self.height()) / 2))
|
|
|
|
|
painter.setFont(font)
|
|
|
|
|
painter.drawText(self.rect(), Qt.AlignCenter, '%d%%' %
|
|
|
|
|
(self.value() / self.maximum() * 100))
|