dynamicpyqt5populateqscrollareamainwindow

Dynamically adding widgets to QScrollArea inside QMainWindow at runtime


I'm trying to populate a QScrollArea object within a MainWindow object at runtime when a menu item is selected. However, I can't seem to figure out how to do this. Here is a minimal example of how I am trying it atm.

Basically, when I select File->Load I want to add 15 Frames each with a checkbox and label to the ScrollArea.

When I run this and select File->Load the terminal throws the error

AttributeError: 'MainWindow' object has no attribute 'scrollArea'

Any help is very much appreciated. This is my first attempt at a pyqt5 project so please forgive the errors.

import sys
from PyQt5.QtGui import QKeySequence
from PyQt5.QtWidgets import (QWidget, QApplication, QLabel,
                            QVBoxLayout, QScrollArea, QGridLayout,
                            QFrame, QHBoxLayout, QCheckBox,
                            QAction, QMainWindow)


class MyScrollWidget(QWidget):

    def __init__(self):
        super(MyScrollWidget, self).__init__()
        lay = QVBoxLayout(self)

        scrollArea = QScrollArea()
        lay.addWidget(scrollArea)

        top_widget = QWidget()
        top_layout = QVBoxLayout()

        top_widget.setLayout(top_layout)
        scrollArea.setWidget(top_widget)

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle('MainWindow')
        self.setGeometry(200, 200, 500, 500)

        self.layout = QGridLayout()

        self.scroll_widget = MyScrollWidget()
        self.layout.addWidget(self.scroll_widget, 0, 0, 1, 10)

        self.central_widget = QWidget()
        self.setCentralWidget(self.central_widget)

        self.central_widget.setLayout(self.layout)

# Set Menu Bar
        self.createActions()
        self.createMenus()

    def createActions(self):
        self.newAct = QAction(  '&New', self, shortcut=QKeySequence.New,
                                statusTip='Create a new file', triggered=self.newFile)

        self.loadAct = QAction(  '&Load', self, shortcut=QKeySequence.New,
                                statusTip='Load a csv file', triggered=self.loadFile)

    def newFile(self):
        pass

    def loadFile(self):
        for i in range(15):
            frame = QFrame()
            layout = QHBoxLayout(frame)

            checkbox = QCheckBox()
            layout.addWidget(checkbox)

            label = QLabel()
            label.setText(f'Label {i}')
            layout.addWidget(label)

            self.scrollArea.addItem(frame)

    def createMenus(self):
        self.fileMenu = self.menuBar().addMenu('&File')
        self.fileMenu.addAction(self.newAct)
        self.fileMenu.addAction(self.loadAct)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

Solution

  • What @musicamante wrote to you may look like this:

    import sys
    from PyQt5.QtGui import QKeySequence
    from PyQt5.QtWidgets import (QWidget, QApplication, QLabel,
        QVBoxLayout, QScrollArea, QGridLayout, QFrame, QHBoxLayout, 
        QCheckBox, QAction, QMainWindow)
    
    
    class MyScrollWidget(QWidget):
        def __init__(self):
            super(MyScrollWidget, self).__init__()
            
            self.top_widget = QWidget()
            self.top_widget.setStyleSheet('background-color: rgb(68, 207, 203);')  #
            self.top_layout = QVBoxLayout(self.top_widget)
    
            self.scrollArea = QScrollArea()
            self.scrollArea.setWidget(self.top_widget)
            
            self.scrollArea.setWidgetResizable(True)               # +++
            
            self.lay = QVBoxLayout(self)
            self.lay.addWidget(self.scrollArea)
    
    
    class MainWindow(QMainWindow):
        def __init__(self, parent=None):
            super().__init__(parent)
            
            self.num = 0                                           # +
            
            self.central_widget = QWidget()
            self.setCentralWidget(self.central_widget)
            
            self.scroll_widget = MyScrollWidget()
            
            self.layout = QGridLayout(self.central_widget)
            self.layout.addWidget(self.scroll_widget, 0, 0, 1, 10)
    
            self.createActions()
            self.createMenus()
    
        def createActions(self):
            self.newAct = QAction('&New', self, 
                shortcut=QKeySequence.New,
                statusTip='Create a new file', 
                triggered=self.newFile)
            self.loadAct = QAction('&Load', self, 
    #            shortcut=QKeySequence.New,
                statusTip='Load a csv file', 
                triggered=self.loadFile)
            self.loadAct.setShortcut('Ctrl+L')                       # +
    
        def newFile(self):
            pass
    
        def loadFile(self):
            for i in range(15):
                frame = QFrame()
                frame.setStyleSheet('background-color: rgb(207, 77, 203);') #
    
                checkbox = QCheckBox()
    
                label = QLabel()
                label.setText(f'Label {i + self.num}')            # + 
    
                layout = QHBoxLayout(frame)            
                layout.addWidget(checkbox)            
                layout.addWidget(label)
    
    # ?            self.scrollArea.addItem(frame)
                self.scroll_widget.top_layout.addWidget(frame)     # +++
    
            self.num += 15                                         # +
    
        def createMenus(self):
            self.fileMenu = self.menuBar().addMenu('&File')
            self.fileMenu.addAction(self.newAct)
            self.fileMenu.addAction(self.loadAct)
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        window = MainWindow()
        window.setWindowTitle('MainWindow')
        window.resize(500, 500)
        window.show()
        sys.exit(app.exec_())
    

    enter image description here

    enter image description here