PyQt通过动画实现平滑滚动的QScrollArea

 

前言

在之前的博客《如何在 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

关于PyQt通过动画实现平滑滚动的QScrollArea的文章就介绍至此,更多相关PyQt QScrollArea内容请搜索编程宝库以前的文章,希望以后支持编程宝库

 使用tkinter实现下拉多选框效果如图:1、选择一些选项2、全选选项代码如下:import tkinterfrom ComBoPicker import Combopickerlist = ...