Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. Smart sizing of QScrollArea
Forum Updated to NodeBB v4.3 + New Features

Smart sizing of QScrollArea

Scheduled Pinned Locked Moved Unsolved Qt for Python
2 Posts 1 Posters 220 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • I Offline
    I Offline
    Insight
    wrote on last edited by Insight
    #1

    I am currently facing a problem regarding the height of my QScrollArea.
    I want to have a layout like this:
    9c5555f0-9743-4e36-a745-bfee8207f7c0-grafik.png
    It is important to note that window height and number of buttons in the QScrollArea can vary. I do not care about the width, because it behaves as expected.
    My requirements are the following:

    • The upper and lower group of buttons should be distributed equally across the height of the parent

    • The QScrollArea should always try to show all of it's contents, when there is extra space available

    • The QScrollArea should not contain any extra space at any time

    • When there is not enough space to show it's contents, the QScrollArea should shrink (preferably up to showing only one button), and have the ability to scroll

    • Inside the QScrollArea the buttons should always be grouped, keeping only the spacing of the layout between each other.

    I have written a minimal example (which can be seen in the screenshot above) fulfilling three (1st, 3rd and 5th) of the requirements:

    import sys
    
    from PyQt5.QtWidgets import (
        QApplication,
        QMainWindow,
        QPushButton,
        QScrollArea,
        QSizePolicy,
        QVBoxLayout,
        QWidget,
    )
    
    
    class MainWindow(QMainWindow):
        def __init__(self):
            super().__init__()
    
            widget = QWidget()
            vbox = QVBoxLayout(widget)
    
            vbox.addWidget(self._init_static())
            vbox.addWidget(self._init_scroll())
    
            self.setCentralWidget(widget)
    
        def _init_static(self):
    
            add = QPushButton("Add Button")
            add.clicked.connect(self.add_button)
            return add
    
        def _init_scroll(self):
    
            content_widget = QWidget()
            content_widget.setSizePolicy(
                QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Maximum
            )
            self.inner_vbox = QVBoxLayout(content_widget)
            scroll_area = QScrollArea()
            scroll_area.setWidgetResizable(True)
            scroll_area.setSizePolicy(
                QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Maximum
            )
            scroll_area.setWidget(content_widget)
            return scroll_area
    
        def add_button(self):
    
            btn = QPushButton("Button")
            btn.setMinimumHeight(30)
            self.inner_vbox.addWidget(btn)
            self.last_widget = btn
    
    
    app = QApplication(sys.argv)
    window = MainWindow()
    window.setGeometry(100, 100, 600, 800)
    window.show()
    sys.exit(app.exec_())
    
    

    Now if you change the vertical SizePolicy of the QScrollArea to "Preferred", it fulfills the 2nd and 5th requirement, but none of the others.

    If you try the example yourself, just click the "Add Button" button to add buttons to the QScrollArea and see the results.

    There seem to be only two Behaviors of the QScrollArea: Either expanding and consuming all extra space, or having a fixed height.

    Does anyone know what I am missing here, or do my requirements clash anywhere and this is not possible?

    1 Reply Last reply
    0
    • I Offline
      I Offline
      Insight
      wrote on last edited by Insight
      #2

      In the mean time I have read some other Threads, apparently also having this problem, but I couldn't find a working solution yet.
      I have discovered the QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents property, but it doesn't seem to change anything.
      Also, I found that setting content_widget SizePolicy to Fixed will prevent the buttons to shrink.
      Anyway, here is an updated example, also with the option to remove the buttons:

      import sys
      
      from PyQt5.QtWidgets import (
          QAbstractScrollArea,
          QApplication,
          QMainWindow,
          QPushButton,
          QScrollArea,
          QSizePolicy,
          QVBoxLayout,
          QWidget,
      )
      
      
      class MainWindow(QMainWindow):
          def __init__(self):
              super().__init__()
      
              widget = QWidget()
              vbox = QVBoxLayout(widget)
      
              vbox.addLayout(self._init_static())
              self.scrollarea = self._init_scroll()
              vbox.addWidget(self.scrollarea)
      
              self.setCentralWidget(widget)
      
          def _init_static(self):
      
              vbox = QVBoxLayout()
              add = QPushButton("Add Button")
              add.clicked.connect(self.add_button)
              clear = QPushButton("Clear Buttons")
              clear.clicked.connect(self.clear_buttons)
              vbox.addWidget(add)
              vbox.addWidget(clear)
              return vbox
      
          def _init_scroll(self):
      
              content_widget = QWidget()
              content_widget.setSizePolicy(
                  QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Fixed
              )
              self.inner_vbox = QVBoxLayout(content_widget)
              scroll_area = QScrollArea()
              scroll_area.setWidgetResizable(True)
              scroll_area.setSizePolicy(
                  QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Maximum
              )
              scroll_area.setSizeAdjustPolicy(
                  QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents
              )
              scroll_area.setWidget(content_widget)
              return scroll_area
      
          def add_button(self):
      
              btn = QPushButton("Remove Button")
              btn.setMinimumHeight(30)
              self.inner_vbox.addWidget(btn)
              btn.clicked.connect(btn.deleteLater)
      
          def clear_buttons(self):
      
              for child in self.scrollarea.widget().children():
                  if isinstance(child, QPushButton):
                      child.deleteLater()
      
      
      app = QApplication(sys.argv)
      window = MainWindow()
      window.setGeometry(100, 100, 600, 800)
      window.show()
      sys.exit(app.exec_())
      
      1 Reply Last reply
      0

      • Login

      • Login or register to search.
      • First post
        Last post
      0
      • Categories
      • Recent
      • Tags
      • Popular
      • Users
      • Groups
      • Search
      • Get Qt Extensions
      • Unsolved