前言

在之前的博客《如何在 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. 13-ORM-更新&删除

    一.更改单个数据 修改单个实体的某些字段 1.查: - 通过get()得到要修改的实体对象 2.改: - 通过对象属性的=的方式修改数据 3.保存 - 通过对象.save()保存数据     二.批量 ...

  2. IPython的使用技巧

    ?打印IPython简介 在IPython中直接输入?,可以打印出IPython的功能介绍 object ?内省功能 在变量后面加上?,可以打印出该变量的详细信息.例如图中一个列表对象,打印出该对象的 ...

  3. 基于 .NET 7 的 QUIC 实现 Echo 服务

    前言 随着今年6月份的 HTTP/3 协议的正式发布,它背后的网络传输协议 QUIC,凭借其高效的传输效率和多路并发的能力,也大概率会取代我们熟悉的使用了几十年的 TCP,成为互联网的下一代标准传输协 ...

  4. Day04:Java数据类型

    Java的数据类型 强类型语言 要求变量的使用要严格符合规定,所有变量都必须先定义后才能使用 弱类型语言 什么是变量 变量:可以变化的量. 在Java中每个变量都必须先申明这个变量是什么类型 Stri ...

  5. Oracle性能优化之运行参数设置

    Oracle参数调整建议值 sessions=2150 processes=2000 open_cursors=5120 db_file_multiblock_read_count=64 log_bu ...

  6. hwlog---huawei.com/npu-exporter/utils---utils.go

    // Copyright(C) 2021. Huawei Technologies Co.,Ltd. All rights reserved.// Package utils offer the so ...

  7. 线程(Thread)基本用法

    一.线程的调用 1.无参 def run_01(): for i in range(6, 10): print("test01", i) time.sleep(1) th_01 = ...

  8. 垃圾回收、python中的流程控制

    垃圾回收机制 1.概念 垃圾回收机制(GC):是Python解释器自带一种机制,专门用来回收不可用的变量值所占用的内存空间 2.原理 Python的垃圾回收机制(GC)主要使用引用计数(referen ...

  9. redisson分布式锁原理剖析

    redisson分布式锁原理剖析 ​ 相信使用过redis的,或者正在做分布式开发的童鞋都知道redisson组件,它的功能很多,但我们使用最频繁的应该还是它的分布式锁功能,少量的代码,却实现了加锁. ...

  10. Referenced file contains errors (http://mybatis.org/dtd/mybatis-3-config.dtd). For more information, right click on the message in the Problems View and select "Show Details..."

    mybatis配置文件报错Referenced file contains errors mybatis的配置文件报错 The errors below were detected when vali ...