PYQT5 使用动画实现平滑滚动的 QScrollArea

实现过程
SmoothScrollBar
滚动过程其实就是改变 QScrollBar 的 value() 的过程,Qt 自带的 QScrollArea 之所以无法平滑滚动,就是因为滚动时在 QScrollBar 的两个 value() 之间进行跳变。如果我们能在两个滚动值之间进行插值,就能实现平滑滚动了,这里通过重写 setValue() 函数来启动滚动动画。

class SmoothScrollBar(QScrollBar):
    """ 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.__value = self.value()
    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 """
    self.__value += value
    self.__value = max(self.minimum(), self.__value)
    self.__value = min(self.maximum(), self.__value)
    self.setValue(self.__value)

def scrollTo(self, value: int):
    """ scroll to the specified position """
    self.__value = value
    self.__value = max(self.minimum(), self.__value)
    self.__value = min(self.maximum(), self.__value)
    self.setValue(self.__value)

def resetValue(self, value):
    self.__value = value

def mousePressEvent(self, e):
    self.ani.stop()
    super().mousePressEvent(e)
    self.__value = self.value()

def mouseReleaseEvent(self, e):
    self.ani.stop()
    super().mouseReleaseEvent(e)
    self.__value = self.value()

def mouseMoveEvent(self, e):
    self.ani.stop()
    super().mouseMoveEvent(e)
    self.__value = self.value()

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())

测试
下面是一个简单的图片查看器测试程序:

# coding:utf-8
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__':![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/2b44af7433e74e5dba9e415b11a1efc5.png)

    app = QApplication(sys.argv)
    w = Demo()
    w.show()
    app.exec_()

测试用的图片如下:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值