我想以动画形式显示QProgressBar
的值变化.
例如,我还没有找到比仅将所有值乘以QProgressBar
0,然后设置过渡动画更好的解决方案.
例如,如果要将值从5更改为4,则进度条动画会将值从5000更改为4000,但显示的是数字5和4,而不是5000和4000.以下是我是如何实现它的:
class CustomProgressBar(QWidget):
def __init__(self,
parent,
curr_value: int,
max_value: int):
super().__init__(parent=parent)
self.MULTIPLIER = 1000
layout = QVBoxLayout(self)
self.progress_bar = self.pg = QProgressBar(self)
self.progress_bar.setTextVisible(True)
self.progress_bar.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.progress_bar.setFixedSize(QSize(1000, 100))
self.progress_bar.setMaximum(max_value * self.MULTIPLIER)
self.progress_bar.setValue(curr_value * self.MULTIPLIER)
displayed_value = int(self.pg.value() / self.MULTIPLIER)
displayed_max_value = int(self.pg.maximum() / self.MULTIPLIER)
self.progress_bar.setFormat(f"{displayed_value}/{displayed_max_value}")
layout.addWidget(self.progress_bar)
# Animation
self.animation = QPropertyAnimation(self.progress_bar, b"value", self.progress_bar)
self.animation.setDuration(500)
self.animation.setEasingCurve(QEasingCurve.Type.OutCubic)
def set_value(self, new_value):
new_value = new_value * self.MULTIPLIER if new_value > 0 else 0
self.animate_value_change(new_value)
displayed_new_value = int(new_value / self.MULTIPLIER)
displayed_max_value = int(self.pg.maximum() / self.MULTIPLIER)
self.progress_bar.setFormat(f"{displayed_new_value}/{displayed_max_value}")
def animate_value_change(self, new_value):
"""Animation of value change"""
# changing text color
if new_value <= self.progress_bar.maximum() / 2:
self.progress_bar.setStyleSheet("QProgressBar {color: white;}")
else:
self.progress_bar.setStyleSheet("QProgressBar {color: black;}")
# animating bar
self.animation.stop()
self.animation.setStartValue(self.progress_bar.value())
self.animation.setEndValue(new_value)
self.animation.start()
下面是它的工作原理: https://youtu.be/tUyuoVAD-KY个
这部动画片的效果有点不稳定和不稳定.
我找到了一个非常奇怪的解决方案:在格式上加%v
:
self.progress_bar.setFormat(f"{displayed_value}/{displayed_total_value} %v")
是的,动画要流畅得多: https://youtu.be/8eOC9xC8K7w个
为什么会是这样呢?有没有可能在不显示真实值QProgressBar
(%v
)的情况下获得同样的流畅度?
Full Python example:个
from PySide6.QtWidgets import QWidget, QProgressBar, QVBoxLayout, QApplication
from PySide6.QtCore import Qt, QPropertyAnimation, QEasingCurve, QObject, Signal, QSize
from threading import Thread
import time
STYLE = """
QProgressBar {
border-radius: 3px;
background-color: rgb(26, 39, 58);
}
QProgressBar::chunk {
border-radius: 3px;
background-color: qlineargradient(spread:pad, x1:0, y1:0.54, x2:1, y2:0.5625, stop:0 rgba(0, 85, 255, 255), stop:1 rgba(8, 255, 227, 255));
}
"""
class CustomProgressBar(QWidget):
def __init__(self,
parent,
curr_value: int,
max_value: int):
super().__init__(parent=parent)
self.MULTIPLIER = 1000
self.setStyleSheet(STYLE)
layout = QVBoxLayout(self)
self.progress_bar = self.pg = QProgressBar(self)
self.progress_bar.setTextVisible(True)
self.progress_bar.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.progress_bar.setFixedSize(QSize(1000, 100))
self.progress_bar.setMaximum(max_value * self.MULTIPLIER)
self.progress_bar.setValue(curr_value * self.MULTIPLIER)
displayed_value = int(self.pg.value() / self.MULTIPLIER)
displayed_max_value = int(self.pg.maximum() / self.MULTIPLIER)
self.progress_bar.setFormat(f"{displayed_value}/{displayed_max_value}")
layout.addWidget(self.progress_bar)
# Animation
self.animation = QPropertyAnimation(self.progress_bar, b"value", self.progress_bar)
self.animation.setDuration(500)
self.animation.setEasingCurve(QEasingCurve.Type.OutCubic)
def set_value(self, new_value):
new_value = new_value * self.MULTIPLIER if new_value > 0 else 0
self.animate_value_change(new_value)
displayed_new_value = int(new_value / self.MULTIPLIER)
displayed_max_value = int(self.pg.maximum() / self.MULTIPLIER)
self.progress_bar.setFormat(f"{displayed_new_value}/{displayed_max_value}")
def animate_value_change(self, new_value):
"""Animation of value change"""
# changing text color
if new_value <= self.progress_bar.maximum() / 2:
self.progress_bar.setStyleSheet("QProgressBar {color: white;}")
else:
self.progress_bar.setStyleSheet("QProgressBar {color: black;}")
# animating bar
self.animation.stop()
self.animation.setStartValue(self.progress_bar.value())
self.animation.setEndValue(new_value)
self.animation.start()
class MyCounter(QObject):
value_changed = Signal(int)
def __init__(self, value: int, step: int = 1):
super().__init__()
self._value = value
self.step = step
@property
def value(self) -> int:
return self._value
@value.setter
def value(self, value: int):
self._value = value if value >= 0 else 0
self.value_changed.emit(self.value)
def make_step(self):
self.value -= self.step
def process(self, delay: int | float):
time.sleep(3)
default_value = self.value
while True:
while self.value:
self.make_step()
time.sleep(delay)
self.value = default_value
time.sleep(delay)
def run(self, delay: int | float = 1):
Thread(target=self.process, args=(delay, ), daemon=True).start()
if __name__ == "__main__":
app = QApplication()
widget = QWidget()
layout = QVBoxLayout(widget)
counter = MyCounter(30, 4)
progress_bar = CustomProgressBar(widget, 30, 30)
counter.value_changed.connect(progress_bar.set_value)
layout.addWidget(progress_bar)
widget.show()
counter.run(1)
app.exec()