Метод QScrollArea.ensureWidgetVisible не показывает целевой виджет - PullRequest
0 голосов
/ 21 сентября 2018

Я пытаюсь сделать последние QPushButton видимыми, используя метод QScrollArea().ensureWidgetVisible(), но, как вы можете видеть, этот метод не прокручивается до последнего 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_()

1 Ответ

0 голосов
/ 21 сентября 2018

Проблема состоит в том, что из соображений эффективности размеры виджетов не рассчитываются и не обновляются до тех пор, пока они не отображаются, в вашем случае область просмотра 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)
...