Search code examples
qtqwidgetqscrollarea

Get QScrollArea absolute size


I have a custom widget that is a child of a QScrollArea. I need to get the absolute size of the QScrollArea, regardless of scrollbars being displayed or not.

class MyWidget : public QWidget { /*...*/ };

void
MyWidget::Foo()
{
    auto scrollAreaHeight = parentWidget()->height();
    auto scrollAreaWidth = parentWidget()->width();

    /* height and width change depending on scrollbars 
       being displayed or not */
}

Is there a way to do this?

Alternatively, if this is impossible trough the QWidget interface returned by the parentWidget() function, is there a way to get a QScrollArea's absolute size from the QScrollArea itself?


Solution

  • I don't understand completely why OP cannot get the absolute size of QScrollArea.

    However, I assume there might be something missing in OP's understanding. I prepared the following small sample:

    A QWidget with a QVBoxLayout with a QScrollArea with a QPushButton:

    #!/usr/bin/python3
    
    import sys
    from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QScrollArea, QPushButton
    
    app = QApplication(sys.argv)
    qWinMain = QWidget()
    qVBox = QVBoxLayout()
    qScrollArea = QScrollArea()
    qBtn = QPushButton("Consume somehow some space\nConsume somehow some space\nConsume somehow some space\n")
    qScrollArea.setWidget(qBtn)
    qVBox.addWidget(qScrollArea)
    qWinMain.setLayout(qVBox)
    qWinMain.show()
    
    def onBtnClicked():
      print("Sizes:")
      print("qWinMain:               ", qWinMain.size())
      print("qWinMain.childrenRect():", qWinMain.childrenRect().size())
      print("qScrollArea:            ", qScrollArea.size())
      print("qScrollArea.viewport(): ", qScrollArea.viewport().size())
      print("qBtn:                   ", qBtn.size())
    
    qBtn.clicked.connect(onBtnClicked)
    sys.exit(app.exec_())
    

    When the QPushButton is clicked, some sizes of the widgets are printed. It did this twice – once when scrollbars are invisible, and again after I changed size of main window so that scrollbars became visible.

    Snapshot 1 (with scrollbars not activated) Snapshot 2 (with scrollbars activated)

    Output:

    Sizes:
    qWinMain:                PyQt5.QtCore.QSize(225, 100)
    qWinMain.childrenRect(): PyQt5.QtCore.QSize(203, 78)
    qScrollArea:             PyQt5.QtCore.QSize(203, 78)
    qScrollArea.viewport():  PyQt5.QtCore.QSize(201, 76)
    qBtn:                    PyQt5.QtCore.QSize(201, 65)
    Sizes:
    qWinMain:                PyQt5.QtCore.QSize(120, 92)
    qWinMain.childrenRect(): PyQt5.QtCore.QSize(98, 70)
    qScrollArea:             PyQt5.QtCore.QSize(98, 70)
    qScrollArea.viewport():  PyQt5.QtCore.QSize(82, 54)
    qBtn:                    PyQt5.QtCore.QSize(201, 65)
    

    So, this is how to read this:

    • qWinMain.size() returned client area size of qWinMain (not considering window decorations).
    • qWinMain.childrenRect().size() returned bounding box size of children of qWinMain – It's exactly 22 pixels smaller in width and height what makes sense as 11 pixels is the default margin of QWidget.
    • qScrollArea.size() returned the exact same size like qWinMain.childrenRect().size() in both cases which is reasonable as it's the only child.
    • qScrollArea.viewport().size() returns the viewport size of QScrollArea – that size is dependend on whether scrollbars are visible or not. Without scrollbars, the difference to qScrollArea is only 2 pixels in width and height but with scrollbars it's respectively greater.
    • qBtn.size() returns size of push button which is independent of its visual/clipped regions and, hence, in both cases equal.

    So, whatever OP meant with "absolute size of QScrollArea" – one of these should be OP is looking for.