Issue
I have QWidget with QVBoxLayout inside QScrollArea like this:
self.vbox = QVBoxLayout()
self.widget = QWidget()
self.widget.setLayout(self.vbox)
self.scroll = QScrollArea()
self.scroll.setWidget(self.widget)
Initially I have four buttons inside this scroll:
# ...Method to insert four buttons...
self.vbox.addStretch()
This keeps all 4 buttons at the top of the scroll area, but if i need to insert another four buttons after start of the program, I do this:
# ...Method to insert four buttons...
self.vbox.addStretch()
# ...Method to insert another four buttons...
And I get this:
But instead I would like to another four buttons to stick to the top as well. Is there a proper way to do this?
Solution
Standard Qt layout managers use QLayoutItems as common abstract objects that are used to lay out everything. Those item objects can be widgets, nested layouts or stretch items.
To the layout manager, they are fundamentally treated in the same way, so a spacer item (QSpacerItem) has the same importance as any other.
What changes is its size policy, which is expanding for addStretch()
, based on its stretch factor. The default factor is 0, meaning that if no other items in the layout have expanding directions, it will try to expand as much as possible.
If you added a stretch item to the bottom of a vertical layout (probably following my own suggestion) you need to consider that you added a further item to the layout: whenever you add other items (like widgets using addWidget()
) they will be appended after the stretch.
So, if you want to keep the widgets pushed on top when adding other items, while respecting the bottom spacer, you must consider its index, which is always equal to layout.count() - 1
. This works similarly to the Python list.insert()
function.
# upon initialization
self.scrollContentLayout.addWidget(someWidget)
...
self.scrollContentLayout.addStretch()
# when called to add further widgets
indexOfSpacer = self.scrollContentLayout.count() - 1
self.scrollContentLayout.insertWidget(indexOfSpacer, anotherWidget)
Another similar possibility is to keep track of the added spacer item:
...
self.scrollContentLayout.addStretch()
self.spacer = self.scrollContentLayout.itemAt(
self.scrollContentLayout.count() - 1)
# then...
self.scrollContentLayout.insertWidget(
self.scrollContentLayout.indexOf(self.spacer), anotherWidget)
Note that, for obvious reasons, the index must be always get dynamically (you cannot "store" it, as other items could be added/inserted in the meantime).
Finally, a simple possibility is to set the layout alignment, without any stretch/spacer item:
self.scrollContentLayout.setAlignment(Qt.Alignment.AlignTop)
While this works for basic widgets, it may have different results if items are added with mixed stretch factors and size policies, so use it with care and awareness about these aspects.
I strongly suggest you to do some proper research about size hints, size policies and general layout management, but also consider to do further testing using Qt Designer and different widget types.
Answered By - musicamante
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.