I have a QScollarea where widgets (rows) can be added or removed dynamically. I would like to avoid jumping around when removing a row (by adding blank space at the bottom if necessary).
For example: I have 5 rows and have scrolled/resized such that rows 2,3,4,5 are shown. Right now, when I remove row 4, rows 1,2,3,5 will be shown. However, I'd like to keep row 2 at the top and add some white space at the bottom so that rows 2,3,5 + a blank row are shown.
I have tried to play around with stretch but could not achieve this behaviour. Any ideas or help would be greatly appreciated!
Here is my code:
from PySide6.QtGui import Qt
from PySide6.QtWidgets import (
QApplication,
QHBoxLayout,
QLineEdit,
QPushButton,
QScrollArea,
QVBoxLayout,
QWidget,
)
class CustomWidget(QWidget):
def __init__(self):
super().__init__()
self.counter = 0
self.widget = QWidget()
self._layout = QVBoxLayout()
self.setLayout(self._layout)
for _ in range(5):
self.add_row()
def add_row(self):
self.counter += 1
add_button = QPushButton("+", None)
add_button.clicked.connect(lambda _: self.add_row())
remove_button = QPushButton("-", None)
remove_button.clicked.connect(
lambda _: self.remove_row_by_button(remove_button)
)
line_edit = QLineEdit(f"{self.counter}")
row_layout = QHBoxLayout()
row_layout.addWidget(add_button, 0, Qt.AlignTop)
row_layout.addWidget(remove_button, 0, Qt.AlignTop)
row_layout.addWidget(line_edit, 0, Qt.AlignTop)
row_layout.addStretch()
self._layout.addLayout(row_layout)
def remove_row_by_button(self, remove_button):
for i in range(self._layout.count()):
row_layout = self._layout.itemAt(i)
if row_layout.itemAt(1).widget() is remove_button:
self.remove_row(i)
return
def remove_row(self, index):
row_layout = self._layout.takeAt(index)
QWidget().setLayout(row_layout) # remove layout by setting it to another widget
class CustomScrollArea(QScrollArea):
def __init__(self):
super().__init__()
self.setWidgetResizable(True)
widget = QWidget()
layout = QVBoxLayout()
layout.addWidget(CustomWidget())
widget.setLayout(layout)
self.setWidget(widget)
if __name__ == "__main__":
app = QApplication([])
sa = CustomScrollArea()
sa.show()
app.exec()
Well one really simple way to do this would be to add some fixed spacing using
layout.addSpacingto the end of the layout each time a row is removed from the scroll area.You will also want to make sure you properly delete the row in your
remove_rowmethod.I made some inline notes where I made changes in the example below.
For example: