I'm trying to make it so that my Window isn't completely occupied by a single QScrollArea.
Basically, I have a Scroll Area, and I want to add something next to it.
I've already seen it created in PySimpleGUI, so I'm sure it can also be created in PySide2, but I'm having trouble creating it. This is where I found the code for the PySimpleGUI. How can I create a column that is scrollable in PySimpleGUI
So far, I've tried to put the QScrollArea and the QVLayoutBox into a QHLayoutBox, with the addLayout() method, which I thought would allow me to put more widgets next to the QScrollArea, but this just gave me the following error.
self.scroll = QScrollArea()
self.hbox = QHBoxLayout()
self.widget = QWidget()
self.vbox = QVBoxLayout()
self.hbox.addLayout(self.vbox)
RuntimeError: QWidget::setLayout: Attempting to set QLayout "" on QWidget "", when the QLayout already has a parent
I've tried searching it on GitHub for some examples, but everything I found was just people expanding their QScrollArea, and not limiting the Scroll Area to a certain part of the window.
Here is a small piece of code I found online that shows the scroll area, with the code that produces my error added in.
from PySide2.QtWidgets import (QWidget, QSlider, QLineEdit, QLabel, QPushButton, QScrollArea,QApplication,
QHBoxLayout, QVBoxLayout, QMainWindow)
from PySide2.QtCore import Qt
from PySide2 import QtWidgets
import sys
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.hbox = QHBoxLayout() # remove this line for the code to work
self.scroll = QScrollArea()
self.widget = QWidget()
self.vbox = QVBoxLayout()
self.hbox.addLayout(self.vbox) # also this line
for i in range(1,50):
object = QLabel("TextLabel")
self.vbox.addWidget(object)
self.widget.setLayout(self.vbox)
self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.scroll.setWidgetResizable(True)
self.scroll.setWidget(self.widget)
self.setCentralWidget(self.scroll)
self.setGeometry(600, 100, 1000, 900)
self.setWindowTitle('Scroll Area Demonstration')
self.show()
return
def main():
app = QtWidgets.QApplication(sys.argv)
main = MainWindow()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Without the lines I added in, a scrollbox is created, however, it takes up the entire window, which isn't what I'm trying to create.
You are misunderstanding the usage of layout managers in Qt.
A layout doesn't do anything on its own, nor it is a overall structure that manages everything: it has to be set on a widget and then it will allow to manage the children of that widget, so it must be created and set within the structure of the widget tree (parent/child relations).
The general structure is this:
The assumption is that a layout only makes sense when set on a widget, in order to manage at least a child widget.
In your case, you are also using a QMainWindow, which requires using a "central widget" containing the central part of the window along with other elements (menu bar, status bar, dock widgets and tool bars). QMainWindow has its own private layout, required to manage the above elements, so if you want to show more than one widget in its center, you need a container widget, set a layout for it, and add the real widgets to it.
The structure you want can be created like this (I'm adding some labels to the scroll area to follow your example image):
The solid lines represent actual QWidgets, while the dashed ones are used for layout managers. Note that QMainWindow has its own internal layout as mentioned above, whereas layouts set on a widget use the same color.
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
central = QWidget()
self.setCentralWidget(central)
mainLayout = QHBoxLayout()
central.setLayout(mainLayout)
# alternatively, you can directly install the layout when creating it
# hbox = QHBoxLayout(central)
self.scroll = QScrollArea()
mainLayout.addWidget(self.scroll)
self.scrollContent = QWidget()
scrollLayout = QVBoxLayout(self.scrollContent)
for i in range(1, 51):
scrollLayout.addWidget(QLabel("Scroll label {}".format(i)))
self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.scroll.setWidgetResizable(True)
self.scroll.setWidget(self.scrollContent)
vbox = QVBoxLayout()
mainLayout.addLayout(vbox)
for i in range(1, 11):
vbox.addWidget(QLabel("Normal label {}".format(i)))
Further notes:
object
is an important Python keyword, and you shall not use it as a variable name;self.resize()
(or eventually implement sizeHint()
), but you should not use arbitrary and hardcoded values for any of that; at the very least, you should compute a possible geometry through QApplication.primaryScreen()
;show()
in the __init__
of a window, as that should only be done externally after the window has been initialized;return
at the end of a function is implicit in Python;