Gabriel Martinez
Gabriel Martinez

Reputation: 53

Setting the scroll bar to the bottom on PyQt5 (using scrollArea and a gridLayout)

I have a QScrollArea with a QGridLayout within. This said QGridLayout is filled with buttons on a 100x100 grid. I want the vertical scrollbar to start on the bottom instead of the top. I've searched online how to do it, but nothing worked so far.

import sys
from PyQt5 import QtWidgets


class IndicSelectWindow(QtWidgets.QDialog):
    def __init__(self, parent=None):
        super(IndicSelectWindow, self).__init__(parent=parent)
        self.resize(500, 400)
        self.layout = QtWidgets.QHBoxLayout(self)
        self.scrollArea = QtWidgets.QScrollArea(self)
        self.scrollArea.setWidgetResizable(True)
        self.scrollAreaWidgetContents = QtWidgets.QWidget()
        self.gridLayout = QtWidgets.QGridLayout(self.scrollAreaWidgetContents)
        self.scrollArea.setWidget(self.scrollAreaWidgetContents)
        self.layout.addWidget(self.scrollArea)

        for i in range(100):
            for j in range(100):
                self.gridLayout.addWidget(QtWidgets.QPushButton(), i, j)



if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    w = IndicSelectWindow()
    w.show()
    sys.exit(app.exec_())

Edit: Trying to explain better - I need to scroll to the bottom so when I open the window, the scrollbar is at the bottom and not at the top.

What I have tried:

x = self.scrollArea.verticalScrollBar().maximum()
self.scrollArea.verticalScrollBar().setValue(x)

and

x = self.scrollArea.verticalScrollBar().maximum()
self.scrollArea.verticalScrollBar().setSliderPosition(x)

Upvotes: 4

Views: 4128

Answers (2)

user18322103
user18322103

Reputation: 61

Although this question has already got an answer, but, I had somewhat similar problem, which was unsolved even after trying the @eyllanesc 's solution.

So, I'm sharing what worked for me.

I got the solution from another post, quick-link https://stackoverflow.com/a/47879340, though his solution is for somewhat different topic.

Solution:

# inside __init__ method
self.scrollArea.verticalScrollBar().rangeChanged.connect(
    self.scrollToBottom,
)

# new function in same class
def scrollToBottom (self, minVal=None, maxVal=None):
    # Additional params 'minVal' and 'maxVal' are declared because
    # rangeChanged signal sends them, but we set it to optional
    # because we may need to call it separately (if you need).
    
    self.scrollArea.verticalScrollBar().setValue(
        self.scrollArea.verticalScrollBar().maximum()
    )

Upvotes: 4

eyllanesc
eyllanesc

Reputation: 244301

The problem is that the scrollbar geometry is updated when:

  • The widget is set to the QScrollArea.
  • The QScrollArea is made visible.
  • The size of the QScrollArea changes.
  • The widget size changes if it is visible.

So when placing the widget first and then the buttons, the QScrollArea is not notified of it, so there are 2 solutions:

  • Move the scrollbar an instant after showing.

        for i in range(100):
            for j in range(100):
                self.gridLayout.addWidget(QtWidgets.QPushButton(), i, j)
        QtCore.QTimer.singleShot(0, self.handle_timeout)
    
    def handle_timeout(self):
        x = self.scrollArea.verticalScrollBar().maximum()
        self.scrollArea.verticalScrollBar().setValue(x)
    
  • Set the widget to the QScrollArea after the buttons were placed.

    class IndicSelectWindow(QtWidgets.QDialog):
        def __init__(self, parent=None):
            super(IndicSelectWindow, self).__init__(parent=parent)
            self.resize(500, 400)
            self.layout = QtWidgets.QHBoxLayout(self)
            self.scrollArea = QtWidgets.QScrollArea(self)
            self.scrollArea.setWidgetResizable(True)
            self.scrollAreaWidgetContents = QtWidgets.QWidget()
            self.gridLayout = QtWidgets.QGridLayout(self.scrollAreaWidgetContents)
    
            self.layout.addWidget(self.scrollArea)
            for i in range(100):
                for j in range(100):
                    self.gridLayout.addWidget(QtWidgets.QPushButton(), i, j)
    
            self.scrollArea.setWidget(self.scrollAreaWidgetContents)
            x = self.scrollArea.verticalScrollBar().maximum()
            self.scrollArea.verticalScrollBar().setValue(x)
    

Upvotes: 1

Related Questions