I just had to deal with the same issue, I figured out a solution that I think is good, although I'm a Qt newbie so take it with a grain of salt:
class MyMainWindow(QWidget):
def __init__(self, parent=None):
super(MyMainWindow, self).__init__(parent)
self.scrollarea = QScrollArea()
# [...]
self.vscrollbar = self.scrollarea.verticalScrollBar()
self.vscrollbar.rangeChanged.connect(self.scrollToBottom)
@Slot(int, int)
def scrollToBottom(self, minimum, maximum):
self.vscrollbar.setValue(maximum)
During construction we connect the rangeChanged
Signal to our custom Slot scrollToBottom
that sets the scrolling value to the maximum value, thereby scrolling down to the bottom every time the contents grow vertically.
I went a step further and made it only scroll to the bottom if the view was scrolled all the way to the bottom before the contents grew:
class MyMainWindow(QWidget):
def __init__(self, parent=None):
super(MyMainWindow, self).__init__(parent)
self.scrollarea = QScrollArea()
# [...]
self.vscrollbar = self.scrollarea.verticalScrollBar()
self.vscrollbar.rangeChanged.connect(self.scrollToBottomIfNeeded)
self.vscrollbar.valueChanged.connect(self.storeAtBottomState)
self.atbottom = True
@Slot(int)
def storeAtBottomState(self, value):
self.atbottom = value == self.vscrollbar.maximum()
@Slot(int, int)
def scrollToBottomIfNeeded(self, minimum, maximum):
if self.atbottom:
self.vscrollbar.setValue(maximum)
In the context of my application, this is the preferred behaviour, as the contents can grow while the user is looking at something in the ScrollArea, so autoscroll would prevent them from staying where they are. If your application only grows the contents after a user action, use the approach in the first snippet.
In response to your comment, this is how to only scroll down when adding an element:
class MyMainWindow(QWidget):
def __init__(self, parent=None):
super(MyMainWindow, self).__init__(parent)
self.scrollarea = QScrollArea()
self.addbutton = QPushButton()
self.addbutton.clicked.connect(self.addElement)
# [...]
self.vscrollbar = self.scrollarea.verticalScrollBar()
self.vscrollbar.rangeChanged.connect(self.scrollToBottomIfNeeded)
self.adding = False
@Slot()
def addElement(self):
self.adding = true
# ... actually add an element ...
@Slot(int, int)
def scrollToBottomIfNeeded(self, minimum, maximum):
if self.adding:
self.vscrollbar.setValue(maximum)
self.adding = False