PyQt通过动画实现平滑滚动的QScrollArea
之一Yo 人气:0前言
在之前的博客《如何在 pyqt 中实现平滑滚动的 QScrollArea》中,我们使用定时器和队列实现了平滑滚动。但是实现代码还是有一点复杂,所以这篇博客将使用 Qt 的动画框架 QPropertyAnimation
来实现相同的功能。
实现过程
SmoothScrollBar
滚动过程其实就是改变 QScrollBar
的 value()
的过程,Qt 自带的 QScrollArea
之所以无法平滑滚动,就是因为滚动时在 QScrollBar
的两个 value()
之间进行跳变。如果我们能在两个滚动值之间进行插值,就能实现平滑滚动了,这里通过重写 setValue()
函数来启动滚动动画。
""" Smooth scroll bar """ scrollFinished = pyqtSignal() def __init__(self, parent=None): QScrollBar.__init__(self, parent) self.ani = QPropertyAnimation() self.ani.setTargetObject(self) self.ani.setPropertyName(b"value") self.ani.setEasingCurve(QEasingCurve.OutCubic) self.ani.setDuration(500) self.ani.finished.connect(self.scrollFinished) def setValue(self, value: int): if value == self.value(): return # stop running animation self.ani.stop() self.scrollFinished.emit() self.ani.setStartValue(self.value()) self.ani.setEndValue(value) self.ani.start() def scrollValue(self, value: int): """ scroll the specified distance """ value += self.value() self.scrollTo(value) def scrollTo(self, value: int): """ scroll to the specified position """ value = min(self.maximum(), max(self.minimum(), value)) self.setValue(value) def mousePressEvent(self, e): self.ani.stop() super().mousePressEvent(e) def mouseReleaseEvent(self, e): self.ani.stop() super().mouseReleaseEvent(e) def mouseMoveEvent(self, e): self.ani.stop() super().mouseMoveEvent(e)
SmoothScrollArea
最后需要将 QScrollArea
的默认滚动条替换为平滑滚动的 SmoothScrollBar
:
class SmoothScrollArea(QScrollArea): """ Smooth scroll area """ def __init__(self, parent=None): super().__init__(parent) self.hScrollBar = SmoothScrollBar() self.vScrollBar = SmoothScrollBar() self.hScrollBar.setOrientation(Qt.Horizontal) self.vScrollBar.setOrientation(Qt.Vertical) self.setVerticalScrollBar(self.vScrollBar) self.setHorizontalScrollBar(self.hScrollBar) def setScrollAnimation(self, orient, duration, easing=QEasingCurve.OutCubic): """ set scroll animation Parameters ---------- orient: Orient scroll orientation duration: int scroll duration easing: QEasingCurve animation type """ bar = self.hScrollBar if orient == Qt.Horizontal else self.vScrollBar bar.ani.setDuration(duration) bar.ani.setEasingCurve(easing) def wheelEvent(self, e): if e.modifiers() == Qt.NoModifier: self.vScrollBar.scrollValue(-e.angleDelta().y()) else: self.hScrollBar.scrollValue(-e.angleDelta().x())
测试
下面是一个简单的图片查看器测试程序:
import sys from PyQt5.QtCore import QEasingCurve, Qt from PyQt5.QtGui import QPixmap from PyQt5.QtWidgets import QApplication, QLabel class Demo(SmoothScrollArea): def __init__(self): super().__init__() self.label = QLabel(self) self.label.setPixmap(QPixmap("shoko.jpg")) # customize scroll animation self.setScrollAnimation(Qt.Vertical, 400, QEasingCurve.OutQuint) self.setScrollAnimation(Qt.Horizontal, 400, QEasingCurve.OutQuint) self.horizontalScrollBar().setValue(1900) self.setWidget(self.label) self.resize(1200, 800) if __name__ == '__main__': app = QApplication(sys.argv) w = Demo() w.show() app.exec_()
最后
至此平滑滚动的实现方式就已介绍完毕了,更多自定义小部件可以参见 PyQt-Fluent-Widgets
加载全部内容