最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解如何在PyQt5中實現(xiàn)平滑滾動的QScrollArea

 更新時間:2023年01月28日 10:07:14   作者:之一Yo  
Qt 自帶的 QScrollArea 滾動時只能在兩個像素節(jié)點之間跳變,看起來很突兀。所以本文將通過定時器,重寫 wheelEvent() 來實現(xiàn)平滑滾動,需要的可以參考一下

平滑滾動的視覺效果

Qt 自帶的 QScrollArea 滾動時只能在兩個像素節(jié)點之間跳變,看起來很突兀。剛開始試著用 QPropertyAnimation 來實現(xiàn)平滑滾動,但是效果不太理想。所以直接開了定時器,重寫 wheelEvent() 來實現(xiàn)平滑滾動。效果如下:

實現(xiàn)思路

定時器溢出是需要時間的,無法立馬處理完所有的滾輪事件,所以自己復(fù)制一個滾輪事件 lastWheelEvent,然后計算每一次滾動需要移動的距離和步數(shù),將這兩個參數(shù)綁定在一起放入隊列中。定時器溢出時就將所有未處理完的事件對應(yīng)的距離累加得到 totalDelta,每個未處理事件的步數(shù)-1,將 totalDelta 和 lastWheelEvent 作為參數(shù)傳入 QWheelEvent的構(gòu)造函數(shù),構(gòu)建出真正需要的滾輪事件 e 并將其發(fā)送到 app 的事件處理隊列中,發(fā)生滾動。

具體代碼

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

最后

也許有人會發(fā)現(xiàn)動圖的界面和 Groove音樂 很像,實現(xiàn)代碼放在了github

到此這篇關(guān)于詳解如何在PyQt5中實現(xiàn)平滑滾動的QScrollArea的文章就介紹到這了,更多相關(guān)PyQt5 QScrollArea內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • python rsa-oaep加密的示例代碼

    python rsa-oaep加密的示例代碼

    這篇文章主要介紹了python rsa-oaep加密示例的示例代碼,幫助大家更好的利用python加解密,感興趣的朋友可以了解下
    2020-09-09
  • 使用python 寫一個靜態(tài)服務(wù)(實戰(zhàn))

    使用python 寫一個靜態(tài)服務(wù)(實戰(zhàn))

    今天小編就為大家分享一篇使用python 寫一個靜態(tài)服務(wù)(實戰(zhàn)),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-06-06
  • Python中Yield的基本用法及Yield與return的區(qū)別解析

    Python中Yield的基本用法及Yield與return的區(qū)別解析

    Python中有一個非常有用的語法叫做生成器,用到的關(guān)鍵字就是yield,這篇文章主要介紹了Python中Yield的基本用法及Yield與return的區(qū)別,需要的朋友可以參考下
    2022-10-10
  • Python圖像處理Pillow庫的安裝使用

    Python圖像處理Pillow庫的安裝使用

    本文詳細介紹了Python第三方庫Pillow的使用,通過導(dǎo)入Pillow庫、打開和保存圖像、基本圖像操作以及圖像處理高級功能的代碼示例,我們了解了Pillow庫的強大功能和靈活性,感興趣的朋友跟隨小編一起看看吧
    2023-07-07
  • Python學(xué)習(xí)_幾種存取xls/xlsx文件的方法總結(jié)

    Python學(xué)習(xí)_幾種存取xls/xlsx文件的方法總結(jié)

    今天小編就為大家分享一篇Python學(xué)習(xí)_幾種存取xls/xlsx文件的方法總結(jié),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • python升級pip及失敗處理方式

    python升級pip及失敗處理方式

    這篇文章主要介紹了python升級pip及失敗處理方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • Python實現(xiàn)ElGamal加密算法的示例代碼

    Python實現(xiàn)ElGamal加密算法的示例代碼

    ElGamal加密算法是一個基于迪菲-赫爾曼密鑰交換的非對稱加密算法。這篇文章通過示例代碼給大家介紹Python實現(xiàn)ElGamal加密算法的相關(guān)知識,感興趣的朋友一起看看吧
    2020-06-06
  • Python?內(nèi)置模塊?argparse快速入門教程

    Python?內(nèi)置模塊?argparse快速入門教程

    argparse模塊是Python內(nèi)置的用于命令項選項與參數(shù)解析的模塊,argparse模塊可以讓人輕松編寫用戶友好的命令行接口,能夠幫助程序員為模型定義參數(shù),這篇文章主要介紹了快速入門Python內(nèi)置模塊argparse,需要的朋友可以參考下
    2023-06-06
  • 淺談Python 函數(shù)式編程

    淺談Python 函數(shù)式編程

    這篇文章主要介紹了Python 函數(shù)式編程的相關(guān)資料,文中講解非常細致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-06-06
  • python-tornado的接口用swagger進行包裝的實例

    python-tornado的接口用swagger進行包裝的實例

    今天小編就為大家分享一篇python-tornado的接口用swagger進行包裝的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-08-08

最新評論

万全县| 龙游县| 乌拉特后旗| 玉环县| 天长市| 海安县| 灵石县| 临夏市| 汉沽区| 曲松县| 上思县| 营山县| 万载县| 内丘县| 马关县| 安阳县| 建昌县| 革吉县| 郴州市| 洮南市| 鄯善县| 合阳县| 富民县| 佳木斯市| 灵武市| 合作市| 沂水县| 南陵县| 若羌县| 玛沁县| 海城市| 钦州市| 南开区| 苍南县| 沙坪坝区| 玉林市| 苗栗县| 姜堰市| 肇庆市| 商水县| 达州市|