QScrollArea.ensureWidgetVisible 方法不显示目标小部件

QScrollArea.ensureWidgetVisible method does not show target widget

我正在尝试使用方法 QScrollArea().ensureWidgetVisible() 使最后一个 QPushButton 可见,但如您所见,此方法不会滚动到最后一个 QPushButton.

例子

能否请您协助解决我的问题,也许是 setFrameStyle 的问题?提前谢谢你。

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


class Widget(QWidget):

    def __init__(self, parent= None):
        super(Widget, self).__init__()
        self.setFixedHeight(200)

        #Container Widget        
        widget = QWidget()
        #Layout of Container Widget
        layout = QVBoxLayout(self)
        for _ in range(20):
            btn = QPushButton("test")
            layout.addWidget(btn)
        widget.setLayout(layout)


        #Scroll Area Properties
        scroll = QScrollArea()
        scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        scroll.setWidgetResizable(False)
        scroll.setWidget(widget)

        # print(scroll.verticalScrollBar().maximum())
        # vbar = scroll.verticalScrollBar()
        # vbar.setValue(vbar.maximum())
        #vbar.setValue(vbar.maximum())


        #Scroll Area Layer add 
        vLayout = QVBoxLayout(self)
        vLayout.addWidget(scroll)
        self.setLayout(vLayout)


        # items = (layout.itemAt(i) for i in range(layout.count())) 
        # for w in items:
        #     print(w)
        print(layout.count())
        #scroll.ensureWidgetVisible(layout.itemAt(layout.count()-5).widget(), xMargin=10, yMargin=10 )
        scroll.ensureWidgetVisible(layout.itemAt(layout.count()-1).widget() )
        print(layout.itemAt(layout.count()-1).widget(),"last widget")


if __name__ == '__main__':
    app = QApplication(sys.argv)
    dialog = Widget()
    dialog.show()

    app.exec_()

问题在于,出于效率原因,小部件的大小在显示之前不会计算或更新,在您的情况下,QScrollArea 的视口尚未更新其大小,因此将滚动条移动到中间位置。一种可能的解决方案是使用 QTimer::singleShot() 在显示后立即调用函数 ensureWidgetVisible()

import sys
from functools import partial
from PyQt5 import QtCore, QtGui, QtWidgets


class Widget(QtWidgets.QWidget):
    def __init__(self, parent= None):
        super(Widget, self).__init__(parent)
        self.setFixedHeight(200)

        #Container Widget        
        widget =QtWidgets.QWidget()
        #Layout of Container Widget
        layout = QtWidgets.QVBoxLayout(widget)
        for _ in range(20):
            btn = QtWidgets.QPushButton("test")
            layout.addWidget(btn)

        scroll = QtWidgets.QScrollArea()
        scroll.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        scroll.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        scroll.setWidgetResizable(False)
        scroll.setWidget(widget)

        #Scroll Area Layer add 
        vLayout = QtWidgets.QVBoxLayout(self)
        vLayout.addWidget(scroll)

        last_widget = layout.itemAt(layout.count()-1).widget()
        QtCore.QTimer.singleShot(0, partial(scroll.ensureWidgetVisible, last_widget))


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

或在之前调用 show()

...
last_widget = layout.itemAt(layout.count()-1).widget() 
self.show()
scroll.ensureWidgetVisible(last_widget)