Как добавить прокрутру содержимого в QGroupBox?

Нужно создать окошко, внутри которого будет GroupBox, в который динамично будут добавляться кнопки.

На случай выхода за пределы границ хочу, чтоб появлялся scroll, но он напрочь отказывается воспринимать мои попытки и отобразиться на экране.

На данный момент я уже и не представляю в чем проблема, надеюсь на помощь, заранее спасибо!

# -*- coding: utf-8 -*-
from PyQt5 import QtCore, QtWidgets
import sys

app = QtWidgets.QApplication(sys.argv)
window = QtWidgets.QWidget()
window.setWindowTitle("Scroll")
window.resize(300,700)

mainbox = QtWidgets.QVBoxLayout() # Сюда поместим GroupBox

vbox = QtWidgets.QVBoxLayout() # Для кнопочек
scroll = QtWidgets.QScrollArea() # Скролиться должен GroupBox
group = QtWidgets.QGroupBox("Check Me") # Этот GroupBox

scroll.setWidget(group) # Для этого я передаю его в ScrollArea

for i in range(50): # Накидываем кнопочки
    vbox.addWidget(QtWidgets.QPushButton("button {}".format(i)))

group.setLayout(vbox) # Закидываем область с кнопками в группу 
mainbox.addWidget(group) # Закидываем группу в главный слой 
window.setLayout(mainbox) # Закрепляем главный слой

window.show()
sys.exit(app.exec_())

Ответы (2 шт):

Автор решения: S. Nick

Я для вам привел более функциональный пример и отметил как правильно делать.

from PyQt5 import QtWidgets, QtGui, QtCore


class GroupBox(QtWidgets.QGroupBox):                  
    clicked = QtCore.pyqtSignal(str, object)     

    def __init__(self, title):              
        super(GroupBox, self).__init__()
        self.title = title
        self.setTitle(self.title)

    def mousePressEvent(self, event):
        child = self.childAt(event.pos())
        if not child:
            child = self
        self.clicked.emit(self.title, child)            


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        self.setWindowTitle("Scroll")
        self.resize(300,700)

        centralWidget = QtWidgets.QWidget()
        layout = QtWidgets.QVBoxLayout()
        centralWidget.setLayout(layout)
        self.setCentralWidget(centralWidget)

        my_tree = QtWidgets.QTreeWidget()
        layout.addWidget(my_tree)

        alpha = QtWidgets.QTreeWidgetItem(my_tree, ['Alpha'])
        beta = QtWidgets.QTreeWidgetItem(my_tree, ['Beta'])
        alpha.addChild(QtWidgets.QTreeWidgetItem(['one']))
        alpha.addChild(QtWidgets.QTreeWidgetItem(['two']))
        beta.addChild(QtWidgets.QTreeWidgetItem(['first']))
        beta.addChild(QtWidgets.QTreeWidgetItem(['second']))

        my_tree.expandAll()
        alpha.child(0).setSelected(True)

# +++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
        scroll = QtWidgets.QScrollArea()
        layout.addWidget(scroll)
        scrollLayout = QtWidgets.QVBoxLayout()

        scrollW = QtWidgets.QWidget()
        scroll.setWidget(scrollW)

        scrollW.setLayout(scrollLayout)
        scrollLayout.setAlignment(QtCore.Qt.AlignTop)

        scroll.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        scroll.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        scroll.setWidgetResizable(True)
# +++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        

        for _ in range(5):
            fooGroup = GroupBox(f'GroupBox_{_}')                                     
            fooGroup.setObjectName(f'fooGroup {_}')
            fooGroup.clicked.connect(self.onFooGroupClick)                 
            fooLayout = QtWidgets.QVBoxLayout()
            fooGroup.setLayout(fooLayout)
            fooItem1 = QtWidgets.QLabel("fooItem1", objectName="fooItem1")
            fooItem1.setStyleSheet('background: #44ffff')
            fooItem2 = QtWidgets.QLabel("fooItem2", objectName="fooItem2")
            fooItem2.setStyleSheet('background: #ffff56;')
            fooItem3 = QtWidgets.QLabel("fooItem3", objectName="fooItem3")
            fooItem3.setStyleSheet('background: #ff42ff;')
            fooLayout.addWidget(fooItem1)
            fooLayout.addWidget(fooItem2)
            fooLayout.addWidget(fooItem3)
            scrollLayout.addWidget(fooGroup)                                     # +++

    def onFooGroupClick(self, title, obj):                                
        print(f"Group: {title}; objectName=`{obj.objectName()}`") 


if __name__ == '__main__':
    app = QtWidgets.QApplication([])
    window = MainWindow()
    window.show()
    app.exec_()

введите сюда описание изображения

Если после изучения будет что-то не понятно, спросите.


Update

import sys
from PyQt5.Qt import *


class Widget(QWidget):
    def __init__(self):
        super().__init__()

        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(True)
        scroll.setWidget(widget)

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


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

введите сюда описание изображения

→ Ссылка
Автор решения: Alexander Chernin

Как сказано в документации

Отметим, что вы должны добавить лейаут виджета до вызова setWidget; если вы добавите его позже, то виджет не будет виден - даже если вызовите show для области прокрутки.

Note that You must add the layout of widget before you call this function; if you add it later, the widget will not be visible - regardless of when you show() the scroll area. In this case, you can also not show() the widget later.

То есть, для появления скрола последовательность команд должна быть такая:

# 1. Установка лейаута для виджета
group.setLayout(vbox) # Закидываем область с кнопками в группу

# 2. Потом уже добавление группы в скрол
scroll.setWidget(group)
→ Ссылка