Python 官方文档:入门教程 => 点击学习
目录平滑滚动的视觉效果实现思路具体代码平滑滚动的视觉效果 Qt 自带的 QScrollArea 滚动时只能在两个像素节点之间跳变,看起来很突兀。刚开始试着用&nb
Qt 自带的 QScrollArea
滚动时只能在两个像素节点之间跳变,看起来很突兀。刚开始试着用 QPropertyAnimation
来实现平滑滚动,但是效果不太理想。所以直接开了定时器,重写 wheelEvent()
来实现平滑滚动。效果如下:
定时器溢出是需要时间的,无法立马处理完所有的滚轮事件,所以自己复制一个滚轮事件 lastWheelEvent
,然后计算每一次滚动需要移动的距离和步数,将这两个参数绑定在一起放入队列中。定时器溢出时就将所有未处理完的事件对应的距离累加得到 totalDelta
,每个未处理事件的步数-1,将 totalDelta
和 lastWheelEvent
作为参数传入 QWheelEvent
的构造函数,构建出真正需要的滚轮事件 e
并将其发送到 app
的事件处理队列中,发生滚动。
from collections import deque
from enum import Enum
from math import cos, pi
from PyQt5.QtCore import QDateTime, Qt, QTimer, QPoint, pyqtSignal
from PyQt5.QtGui import QWheelEvent
from PyQt5.QtWidgets import QApplication, QScrollArea
class ScrollArea(QScrollArea):
""" A scroll area which can scroll smoothly """
def __init__(self, parent=None, orient=Qt.Vertical):
"""
Parameters
----------
parent: QWidget
parent widget
orient: Orientation
scroll orientation
"""
super().__init__(parent)
self.orient = orient
self.fps = 60
self.duration = 400
self.stepsTotal = 0
self.stepRatio = 1.5
self.acceleration = 1
self.lastWheelEvent = None
self.scrollStamps = deque()
self.stepsLeftQueue = deque()
self.smoothMoveTimer = QTimer(self)
self.smoothMode = SmoothMode(SmoothMode.LINEAR)
self.smoothMoveTimer.timeout.connect(self.__smoothMove)
def setSmoothMode(self, smoothMode):
""" set smooth mode """
self.smoothMode = smoothMode
def wheelEvent(self, e):
if self.smoothMode == SmoothMode.NO_SMOOTH:
super().wheelEvent(e)
return
# push current time to queque
now = QDateTime.currentDateTime().toMSeCSSinceEpoch()
self.scrollStamps.append(now)
while now - self.scrollStamps[0] > 500:
self.scrollStamps.popleft()
# adjust the acceration ratio based on unprocessed events
accerationRatio = min(len(self.scrollStamps) / 15, 1)
if not self.lastWheelEvent:
self.lastWheelEvent = QWheelEvent(e)
else:
self.lastWheelEvent = e
# get the number of steps
self.stepsTotal = self.fps * self.duration / 1000
# get the moving distance corresponding to each event
delta = e.angleDelta().y() * self.stepRatio
if self.acceleration > 0:
delta += delta * self.acceleration * accerationRatio
# fORM a list of moving distances and steps, and insert it into the queue for processing.
self.stepsLeftQueue.append([delta, self.stepsTotal])
# overflow time of timer: 1000ms/frames
self.smoothMoveTimer.start(1000 / self.fps)
def __smoothMove(self):
""" scroll smoothly when timer time out """
totalDelta = 0
# Calculate the scrolling distance of all unprocessed events,
# the timer will reduce the number of steps by 1 each time it overflows.
for i in self.stepsLeftQueue:
totalDelta += self.__subDelta(i[0], i[1])
i[1] -= 1
# If the event has been processed, move it out of the queue
while self.stepsLeftQueue and self.stepsLeftQueue[0][1] == 0:
self.stepsLeftQueue.popleft()
# construct wheel event
if self.orient == Qt.Vertical:
p = QPoint(0, totalDelta)
bar = self.verticalScrollBar()
else:
p = QPoint(totalDelta, 0)
bar = self.horizontalScrollBar()
e = QWheelEvent(
self.lastWheelEvent.pos(),
self.lastWheelEvent.globalPos(),
QPoint(),
p,
round(totalDelta),
self.orient,
self.lastWheelEvent.buttons(),
Qt.NoModifier
)
# send wheel event to app
QApplication.sendEvent(bar, e)
# stop scrolling if the queque is empty
if not self.stepsLeftQueue:
self.smoothMoveTimer.stop()
def __subDelta(self, delta, stepsLeft):
""" get the interpolation for each step """
m = self.stepsTotal / 2
x = abs(self.stepsTotal - stepsLeft - m)
res = 0
if self.smoothMode == SmoothMode.NO_SMOOTH:
res = 0
elif self.smoothMode == SmoothMode.CONSTANT:
res = delta / self.stepsTotal
elif self.smoothMode == SmoothMode.LINEAR:
res = 2 * delta / self.stepsTotal * (m - x) / m
elif self.smoothMode == SmoothMode.QUADRATI:
res = 3 / 4 / m * (1 - x * x / m / m) * delta
elif self.smoothMode == SmoothMode.COSINE:
res = (cos(x * pi / m) + 1) / (2 * m) * delta
return res
class SmoothMode(Enum):
""" Smooth mode """
NO_SMOOTH = 0
CONSTANT = 1
LINEAR = 2
QUADRATI = 3
COSINE = 4
最后
也许有人会发现动图的界面和 Groove音乐 很像,实现代码放在了GitHub。
到此这篇关于详解如何在PyQt5中实现平滑滚动的QScrollArea的文章就介绍到这了,更多相关PyQt5 QScrollArea内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
--结束END--
本文标题: 详解如何在PyQt5中实现平滑滚动的QScrollArea
本文链接: https://www.lsjlt.com/news/178480.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
下载Word文档到电脑,方便收藏和打印~
2024-03-01
2024-03-01
2024-03-01
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0