向 QScrollArea 添加元素时滚动到底部

问题描述 投票:0回答:2

我有一个 QScrollArea,我希望当我按下“添加”按钮时,将小部件添加到 QScrollArea 中包含的小部件中,以便滚动一直滚动到底部

我多次尝试使用类似代码滚动到底部

   scrollWidget.update()
   bar = scrollWidget.verticalScrollBar()
   bar.setValue(bar.maximum())

或者甚至使用

ensureWidgetVisible
但似乎发生的事情是它滚动到滚动的底部“在调整大小发生之前”,然后它调整大小,所以我不太在底部。

我通过编写检查条形大小、最大条形大小和子项计数的代码来验证这一点 这表明有新的子项,但条形大小尚未更新。

然后我尝试先通过调用给 Qt 时间“重新计算”大小:

   QApplication.processEvents()
   scrollWidget.update()

我不希望滚动区域始终位于底部,但仅在按下按钮后

python pyqt qscrollarea
2个回答
1
投票

我不得不处理同样的问题,我找到了一个我认为很好的解决方案,尽管我是 Qt 新手,所以对此持保留态度:

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)

在构建过程中,我们将

rangeChanged
信号连接到我们的自定义插槽
scrollToBottom
,将滚动值设置为最大值,从而在每次内容垂直增长时向下滚动到底部。

我更进一步,如果在内容增长之前视图一直滚动到底部,则仅滚动到底部:

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)

在我的应用程序的上下文中,这是首选行为,因为当用户在 ScrollArea 中查看某些内容时,内容会增长,因此自动滚动会阻止它们停留在原来的位置。如果您的应用程序仅在用户操作后增加内容,请使用第一个片段中的方法。

响应您的评论,这是添加元素时仅向下滚动的方法:

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

0
投票

我做了一些实验,改变了方法调用的顺序。但我仍然不明白到底什么时候值得调用滚动更改。我写了糟糕的代码,但它有效。

def scroll_to_bottom(self):
    for i in range(2): # range(3) or range(4), range(2) works for me
        QApplication.processEvents()
        self.scrollArea_messages.update()
        cur_max = self.scrollArea_messages.verticalScrollBar().maximum()
        self.scrollArea_messages.verticalScrollBar().setValue(cur_max)
© www.soinside.com 2019 - 2024. All rights reserved.