pythonpyqtpyqt5qscrollareaqscrollbar

Auto-scroller in QScrollArea?


I have created an AutoScroller inside my Gallery but there seems to be a bug that keeps accelerating the speed of scrolling which makes the speed spinbox so unaccurate.

My Idea of autoscrolling is using the QTimer

from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *

class Main(object):
    def setupUI(self, Project):

Project = QWidget() Assigned from the outer scope and referenced

        Project.setFixedSize(QSize(900, 400))
        self.mainScroll = QScrollArea(Project)
        self.mainScroll.setGeometry(QRect(80, 0, 740, 400))
        self.mainScrollWidget = QWidget()
        self.layout = QVBoxLayout(self.mainScrollWidget)
        self.layout.addStretch()
        self.layout.setGeometry(
            QRect(0, 0, self.mainScroll.width(), self.mainScroll.height()))
        self.mainScroll.setWidget(self.mainScrollWidget)

        self.checkBox = QCheckBox("Auto-Scroll", Project)
        self.checkBox.setGeometry(QRect(0, 0, 80, 30))
        self.checkBox.toggled.connect(lambda: self.StartTimer(Project))

        self.PX_PER_TIME = 1
        self.Speed = 10

        for i in range(200):
            MainWidget = QWidget()
            label = QLabel("LABEL NO_%s" % str(i), MainWidget)
            label.adjustSize()
            self.layout.setSizeConstraint(QLayout.SetFixedSize)
            self.layout.addStretch(1)
            self.layout.addWidget(MainWidget)

    def ScrollDown(self):
        vScrollBar = self.mainScroll.verticalScrollBar()
        vScrollBar.setValue(vScrollBar.value() + self.PX_PER_TIME)

    def StartTimer(self, Project):
        if self.checkBox.isChecked():
            self.timeleft = self.Speed
            qTimer = QTimer(Project)
            qTimer.timeout.connect(self.TimerTimout)
            qTimer.start(1)
            self.ScrollDown()
        else:
            if type(qTimer) != None:
                qTimer.stop()
                self.timeleft = self.Speed

    def TimerTimout(self):
        if self.timeleft > 0:
            self.timeleft -= 1
        if self.timeleft == 0:
            self.timeleft = self.Speed
            self.ScrollDown()

Edit

This should reproduce my problem and it kinda explains the type of solution, What I am trying to accomplish is completely stopping the QTimer once the QCheckBox is disabled and reassign all variables to their base state and stop the scrollbar from scrolling.


Solution

  • here goes my answer. I've implemented a simple example built from the top of your question example. I fixed some syntax error and removed some unnecessary code. I hope it helps you out.

    from PyQt5 import QtCore, QtGui, QtWidgets
    
    
    class Main(QtWidgets.QWidget):
        def __init__(self):
            super(Main, self).__init__()
    
            self.speed = QtWidgets.QSpinBox(self)
            self.speed.setValue(10)
    
            self.autoscroll = QtWidgets.QCheckBox(self)
    
            self.imageLabel = QtWidgets.QLabel()
            self.image = QtGui.QImage("test.jpg")
            self.imageLabel.setPixmap(QtGui.QPixmap.fromImage(self.image))
    
            self.ScrollArea = QtWidgets.QScrollArea()
            self.ScrollArea.setBackgroundRole(QtGui.QPalette.Dark)
            self.ScrollArea.setWidget(self.imageLabel)
    
            self.autoscroll.toggled.connect(self.toggleTimer)
            self.layout = QtWidgets.QVBoxLayout()
            self.layout.addWidget(self.speed)
            self.layout.addWidget(self.autoscroll)
            self.layout.addWidget(self.ScrollArea)
            self.setLayout(self.layout)
    
            self.qTimer = QtCore.QTimer(self)
            self.qTimer.timeout.connect(self.timerTimout)
    
        def toggleTimer(self):
            if self.qTimer.isActive():
                self.stopTimer()
            else:
                self.startTimer()
    
        def stopTimer(self):
            self.qTimer.stop()
    
        def startTimer(self):
            self.qTimer.start(1)
    
        def timerTimout(self):
            self.scrollDown()
    
        def scrollDown(self):
            scrollBar = self.ScrollArea.verticalScrollBar()
            scrollBar.setValue(scrollBar.value() + self.speed.value())
    
    
    if __name__ == "__main__":
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
        widget = Main()
        widget.show()
        sys.exit(app.exec_())
    

    P.S. I've implemented an option to stop scrolling. :)