0

I'm trying to learn pyqt5 in python by creating a small application. For one of the windows, I need to add a vertical scroll bar to the window. Now, this window has a table made using QLabel and QLineEdit. Check the picture to get exactly how it looks like.Table-Picture

As you can see there are a lot of chemicals, which goes below the window screen. I have tried numerous approaches but somehow couldn't get the result. If I am able to get the scroll, all the elements get aligned one under another (QVBoxLayout) which is not the way I want the elements to be aligned.

Here's the code I'm using

class ChemicalWindow(QWidget):
    def __init__(self,chemicals,data):
        super().__init__()

        self.layout = QVBoxLayout()
        self.setWindowTitle("Chemicals")
        self.setMinimumSize(QSize(600,600))
        self.setStyleSheet("background-color:#eaf4f4;")
        self.chemicals = chemicals
        self.data = data

        self.createBody()
        self.createButtons()

    def createBody(self):

        headerLabel = QLabel('Chemicals',scroll_widget)
        headerLabel.move(265,10)
        headerLabel.resize(70,40)
        headerLabel.setStyleSheet("color:#000;")

        tcLabel = QLabel('Tc',scroll_widget)
        tcLabel.move(200,50)
        tcLabel.resize(60,30)
        tcLabel.setStyleSheet("color:#000;")

        pcLabel = QLabel('Pc',scroll_widget)
        pcLabel.move(280,50)
        pcLabel.resize(60,30)
        pcLabel.setStyleSheet("color:#000;")

        cpLabel = QLabel('Cp',scroll_widget)
        cpLabel.move(360,50)
        cpLabel.resize(60,30)
        cpLabel.setStyleSheet("color:#000;")

        self.chemical_names = self.chemicals.keys()

        y_position = 90

        # List for keeping chemical inputs variables in form of dict of list -> {A:[chemical_a_tc,chemical_a_pc,chemical_a_cp],
        #                                                                        B:[chemical_b_tc,chemical_b_pc,...],...}
        self.chemical_inputs = dict()

        # Creating labels for the chemical names
        for name in self.chemical_names:
            chemicalLabel = QLabel(name,scroll_widget)
            chemicalLabel.move(70,y_position)
            chemicalLabel.resize(75,30)
            chemicalLabel.setStyleSheet("color:#000;")
            chemicalLabel.setToolTip(name)
            y_position += 40

            current_chemical_inputs = dict()
            for chemical_input in self.chemicals[name]:
                current_chemical_inputs[chemical_input] = QLineEdit(scroll_widget) 
            self.chemical_inputs[name] = current_chemical_inputs

        position_y = 90
        for individual_chemical in self.chemical_inputs:
            position_x = 160
            for chemical_input in self.chemical_inputs[individual_chemical]:
                self.chemical_inputs[individual_chemical][chemical_input].setText(str(self.data['chemicals'][individual_chemical][chemical_input]))
                self.chemical_inputs[individual_chemical][chemical_input].move(position_x,position_y)
                self.chemical_inputs[individual_chemical][chemical_input].resize(80,30)
                self.chemical_inputs[individual_chemical][chemical_input].setStyleSheet("color:#000;background-color:#a9d6e5;padding:2px;")
                
                position_x += 90                
            position_y += 40

    def createButtons(self):
        close_button = QPushButton('Close',self)
        close_button.move(510,550)
        close_button.resize(70,30)
        close_button.setStyleSheet("background-color:#00509d;color:#fff;")
        close_button.clicked.connect(self.closeButton)

    def closeButton(self):
        self.close()


What am I doing wrong?

2
  • 3
    1. use QScrollArea; 2. use QGridLayout, or nested layouts (multiple QHBoxLayout added to the main QVBoxLayout), set for a container QWidget that you'll add to QScrollArea. Remember to use setWidgetResizable(True). Commented Feb 6, 2023 at 19:20
  • Thanks. I tried it using a combination of QHBoxLayout as columns and QVBoxLayout as rows. Commented Feb 9, 2023 at 19:47

1 Answer 1

1

Firstly, instead of using .move() to manually place your widgets, you should be using a QLayout (ex. QHBoxLayout or QVBoxLayout). This will automatically space your labels, and you can modify it by adjusting stretch and adding spacers (QSpacerItem). For more complex layouts, you can either nest multiple box layouts, or use a QGridLayout.

Now to address the scrolling: First, you want to create your scroll area. Make this widget the central widget. Remember to set setWidgetResizable to True.

scroller = QScrollArea()
scroller.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
scroller.resize(self.width(),self.height())
scroller.setWidgetResizable(True)
self.setCentralWidget(scroller)

Next, create your container and add it to the scroll area. All your layout elements (labels, buttons, etc.) should be placed in this container.

self.container = QWidget()
scroller.setWidget(self.container)

Here's the full sample program I created:

import sys
from PyQt5.QtWidgets import QMainWindow, QWidget, QScrollArea, QVBoxLayout, QLabel, QApplication
from PyQt5.QtCore import Qt

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.resize(1100, 800)

        scroller = QScrollArea()
        scroller.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOn)

        self.container = QWidget()
        scroller.setWidget(self.container)
        scroller.resize(self.width(),self.height())
        scroller.setWidgetResizable(True)
        self.setCentralWidget(scroller)
        
        self.holderColumn=QVBoxLayout()
    
        txtList=["apple","banana","orange","triangle","circle","square","moon","star","sun","delta"]
        objs=list()
        for i in txtList:
            tempLabel=QLabel()
            tempLabel.setText(i)
            tempLabel.setFixedSize(300,300)
            objs.append(tempLabel)
            self.holderColumn.addWidget(tempLabel)        
        self.container.setLayout(self.holderColumn)
        
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
Sign up to request clarification or add additional context in comments.

2 Comments

That central widget is completely useless, and the scroll area won't resize when the window is. Remove central_widget and just use self.setCentralWidget(scroller).
@musicamante Great, thank you for the tip! And an extra thank you for not being condescending, I'm still learning in PyQt5 haha.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.