在 PyQt5 上将滚动条设置到底部(使用 scrollArea 和 gridLayout)

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

我有一个带有 QGridLayout 的 QScrollArea。这表示 QGridLayout 在 100x100 网格上充满了按钮。我希望垂直滚动条从底部而不是顶部开始。我在网上搜索了如何操作,但到目前为止没有任何效果。

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_())

编辑:试图更好地解释 - 我需要滚动到底部,所以当我打开 window 时,滚动条在底部而不是在顶.

我尝试过的:

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

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

问题是滚动条几何图形在以下时间更新:

  • 小部件设置为 QScrollArea。
  • QScrollArea 可见。
  • QScrollArea 的大小发生变化。
  • 如果小部件可见,它的大小会发生变化。

所以先放widget再放按钮的时候,QScrollArea是不会被通知的,所以有2种解决方法:

  • 显示后立即移动滚动条。

        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)
    
  • 放置按钮后将小部件设置为 QScrollArea。

    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)
    

虽然这个问题已经有了答案,但是,我遇到了一些类似的问题,即使尝试了@eyllanesc 的解决方案也没有解决。

所以,我正在分享对我有用的东西。

我从另一个 post、quick-link 那里得到了解决方案,尽管他的解决方案针对的主题有所不同。

解决方案:

# 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()
    )