前言

在之前的博客《如何在 pyqt 中实现平滑滚动的 QScrollArea》中,我们使用定时器和队列实现了平滑滚动。但是实现代码还是有一点复杂,所以这篇博客将使用 Qt 的动画框架 QPropertyAnimation 来实现相同的功能。

实现过程

SmoothScrollBar

滚动过程其实就是改变 QScrollBarvalue() 的过程,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.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())

测试

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

# 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__':
app = QApplication(sys.argv)
w = Demo()
w.show()
app.exec_()

测试用的图片如下(硝子酱真可爱:

写在最后

至此平滑滚动的实现方式就已介绍完毕了,更多自定义小部件可以参见 PyQt-Fluent-Widgets,以上~~

如何在 pyqt 中使用动画实现平滑滚动的 QScrollArea的更多相关文章

  1. 如何在pyqt中在实现无边框窗口的同时保留Windows窗口动画效果(一)

    无边框窗体的实现思路 在pyqt中只要 self.setWindowFlags(Qt.FramelessWindowHint) 就可以实现边框的去除,但是没了标题栏也意味着窗口大小无法改变.窗口无法拖 ...

  2. 如何在pyqt中实现带动画的动态QMenu

    弹出菜单的视觉效果 QLineEdit 原生的菜单弹出效果十分生硬,而且样式很丑.所以照着Groove中单行输入框弹出菜单的样式和动画效果写了一个可以实现动态变化Item的弹出菜单,根据剪贴板的内容是 ...

  3. 如何在pyqt中自定义无边框窗口

    前言 之前写过很多关于无边框窗口并给窗口添加特效的博客,按照时间线罗列如下: 如何在pyqt中实现窗口磨砂效果 如何在pyqt中实现win10亚克力效果 如何在pyqt中通过调用SetWindowCo ...

  4. 如何在pyqt中通过调用 SetWindowCompositionAttribute 实现Win10亚克力效果

    亚克力效果 在<如何在pyqt中实现窗口磨砂效果>和<如何在pyqt中实现win10亚克力效果>中,我们调用C++ dll来实现窗口效果,这种方法要求电脑上必须装有MSVC.V ...

  5. 如何在pyqt中给无边框窗口添加DWM环绕阴影

    前言 在之前的博客<如何在pyqt中通过调用SetWindowCompositionAttribute实现Win10亚克力效果>中,我们实现了窗口的亚克力效果,同时也用SetWindowC ...

  6. 如何在pyqt中实现窗口磨砂效果

    磨砂效果的实现思路 这两周一直在思考怎么在pyqt上实现窗口磨砂效果,网上搜了一圈,全都是 C++ 的实现方法.正好今天查python的官方文档的时候看到了 ctypes 里面的 HWND,想想倒不如 ...

  7. 如何在pyqt中实现win10亚克力效果

    亚克力效果的实现思路 上一篇博客<如何在pyqt中实现窗口磨砂效果> 中实现了win7中的Aero效果,但是和win10的亚克力效果相比,Aero还是差了点内味.所以今天早上又在网上搜了一 ...

  8. 如何在 pyqt 中捕获并处理 Alt+F4 快捷键

    前言 如果在 Windows 系统的任意一个窗口中按下 Alt+F4,默认行为是关闭窗口(或者最小化到托盘).对于使用了亚克力效果的窗口,使用 Alt+F4 最小化到托盘,再次弹出窗口的时候可能出现亚 ...

  9. 如何在pyqt中实现平滑滚动的QScrollArea

    平滑滚动的视觉效果 Qt 自带的 QScrollArea 滚动时只能在两个像素节点之间跳变,看起来很突兀.刚开始试着用 QPropertyAnimation 来实现平滑滚动,但是效果不太理想.所以直接 ...

  10. 如何在pyqt中使用 QGraphicsView 实现图片查看器

    前言 在 PyQt 中可以使用很多方式实现照片查看器,最朴素的做法就是重写 QWidget 的 paintEvent().mouseMoveEvent 等事件,但是如果要在图像上多添加一些形状,那么在 ...

随机推荐

  1. 二、docker安装

    一.docker安装 Docker 是管理容器的工具, Docker 不等于 容器. 1.1.docker yum源设置 #step 1 download docker-ce.repo file [r ...

  2. 创建.NET程序Dump的几种姿势

    当一个应用程序运行的有问题时,生成一个Dump文件来调试它可能会很有用.在Windows.Linux或Azure上有许多方法可以生成转储文件. Windows平台 dotnet-dump (Windo ...

  3. C# Interlocked 类

    [前言] 在日常开发工作中,我们经常要对变量进行操作,例如对一个int变量递增++.在单线程环境下是没有问题的,但是如果一个变量被多个线程操作,那就有可能出现结果和预期不一致的问题. 例如: stat ...

  4. js高级基础部分

    基于尚硅谷的尚硅谷JavaScript高级教程提供笔记撰写,加入一些个人理解 github源码 博客下载 数据类型的分类和判断 主要问题 分类 基本(值)类型 Number ----- 任意数值 -- ...

  5. vue3 结合 element-plus 框架实现增删改查功能(不连接数据库)

    一.效果图 二.代码 2.1.导入依赖(已经安装过node.js) npm install element-plus --save 注意:要是安装失败,可以使用淘宝镜像进行下载,如下: 2.2.设置淘 ...

  6. Python冷知识:如何找出新版本增加或删除了哪些标准库?

    "内置电池"是 Python 最为显著的特性之一,它提供了 200 多个开箱即用的标准库.但是,历经了 30 多年的发展,很多标准库已经成为了不得不舍弃的历史包袱,因为它们正在&q ...

  7. (C++) C++ 中 shared_ptr weak_ptr

    shared_ptr std::shared_ptr<int> sp1 = new int(); // shared count = 1, weak count = 0 std::shar ...

  8. (GCC) gcc编译选项 -Wl, -start-group,whole-archive,-Wl, Bstatic

    1. start-group 编译选项 假设程序x依赖三个静态库:libX1.a.libX2.a和libX3.a,而libX2.a又依赖libX1.a,libX3.a依赖libX2.a和libX1.a ...

  9. linux sublime-text ctrl+shift+b 快捷键失效问题解决

    解决办法 由于fcitx拦截了这个ctrl+shift+b 这个快捷键,所以取消即可 点击全局配置里面高级选项,然后找到ctrl+shift+b这个快捷键,点击后,按esc就可以将快捷键设置为空,不过 ...

  10. 【接口测试】Postman(一)--接口测试知识准备

    1.0 前言 ​ 应用程序编程接口(Application Programming Interface, API)是这些年来最流行的技术之一,强大的Web应用程序和领先的移动应用程序都离不开后端强大的 ...