QScrollArea sizing issue



  • I'm struggling with a QScrollArea sizing issue, and would appreciate a hint. I'm a newb, I'm pretty tired working on this. So please excuse me.

    I started from existing code in a large program with a QDialog containing a QVBoxLayout with many controls. In outline:

    # self == QDialog
    self.vertLayout = QVBoxLayout(self)
    ...
    

    This gave me a dialog as wide/high as needed for content, limited to dialog size, but had so much vertical content it was off the bottom.

    All I need is a vertical scroller inside dialog around content to make it reasonable. After a bit of a struggle (and some help to finally find a simple example at https://stackoverflow.com/a/28826793/489865), I have moved to:

    # self == QDialog
    scrollArea = QScrollArea(self)
    scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
    scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
    # scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
    scrollArea.setWidgetResizable(True)
    scrollArea.setFixedHeight(400)
    
    widget = QWidget()
    scrollArea.setWidget(widget)
    
    self.vertLayout = QVBoxLayout()
    widget.setLayout(self.vertLayout)
    ...
    

    This is great, in that vertically I get the scrollbar I need. However, the bit I don't get is that I also now have the horizontal content's width limited, such that it needs a horizontal scrollbar and/or it gets truncated horizontally. In short, horizontally it nowhere near fills the width of the dialog any longer.

    0_1507909934462_Screenshot from 2017-10-13 16-50-44.png
    I don't understand to what or why there is a horizontal limit being applied here? I've played a bit with code & debugger but no wiser.

    I'd like the content to take up as much room horizontally as it used to, but limit the verticality to require scrolling. Please.


  • Qt Champions 2016

    @JNBarchan said in QScrollArea sizing issue:

    Hi
    first of all
    this reads funny

    self.vertLayout = QVBoxLayout()
    widget.setLayout(self.vertLayout)

    ahh no. just pyt confusing me . its the same as
    VBoxLayout *layout = new QVBoxLayout();
    if layout is a class member.
    like you give the dialogs layout to the widget ?
    Maybe just syntax. They cannot share a layout.

    anyway, can you try to insert the scrollarea into the dialogs layout ?

    self.layout().addWidget( ScrollArea);

    The code you link to suffer the same

    alt text

    The dialog have no layout of its own and hence it wont use all of dialogs size.

    I think you have same issue as
    self.vertLayout = QVBoxLayout()
    widget.setLayout(self.vertLayout)

    creates the layout and give to widget ?

    so seems the SELF dialog have no layout and hence wont make
    scroll area take up all space.



  • @mrjj
    I will try your suggestion as soon as I am able.

    However, although I confess I could be misunderstanding, the reason I didn't think that was necessary is because of http://doc.qt.io/qt-5/qwidget.html#setLayout:

    void QWidget::setLayout(QLayout *layout)
    An alternative to calling this function is to pass this widget to the layout's constructor.

    So "to insert the scrollarea into the dialogs layout " you want:
    self.layout().addWidget(scrollArea);
    and I already have:
    scrollArea = QScrollArea(self)
    (not just QScrollArea() constructor) which I understand to do same thing as calling setLayout(scrollArea) explicitly, no?


  • Lifetime Qt Champion

    Hi,

    No, not at all. With scrollArea = QScrollArea(self) you are just giving it a parent and when you call show on it, it will be shown in the parent viewport.

    With setLayout(scrollArea), that's just wrong. You can't set a widget as layout.

    So neither are doing what you want.

    In the constructor of your dialog you should have something like:

    layout = QVBoxLayout()
    layout->addWidget(scrollArea)
    self.setLayout(layout)
    

    or the short version:

    layout = QVBoxLayout(self) # Create a layout and apply it to it's parent
    layout->addWidget(scrollArea)
    


  • @SGaist
    Thanks for this, when I get back to code I will review in this light.

    Does that indeed mean that the example I copied from, https://stackoverflow.com/a/28826793/489865, is not right, as @mrjj was suggesting? That posts says, and I (thought I) followed the code:

    •on the bottom is parent widget (for example QDialog)
    •on top of this is scrollable area (QScrollArea) of fixed size

    i.e. scrollarea straight on dialog, you are putting it on layout, he does not do that? I am getting really confused with the layers of widgets/layouts/scrollareas... :(


  • Lifetime Qt Champion

    No, the content of the widget is described correctly on that post.

    The two points of interest:

    • on the bottom is parent widget (for example QDialog)
    • on top of this is scrollable area (QScrollArea) of fixed size

    You see ? No layouts involved there. The fact that it's passing a parent to the QScrollArea makes it appear within the dialog.



  • @SGaist
    Thanks, but I thought I was to do the same as him, yet in mine you're telling me I need a QVBoxLayout that he does not need.....

    I started with a dialog with a vboxlayout and some content. My content overflows the dialog vertically. I want to have a vertical scrollbar against the side of the dialog for its content. That's all I want to add to the original code. I'm finding this mega-complex.... :(


  • Lifetime Qt Champion

    What the examples shows is how a QScrollArea work not how to make it fit in a widget.

    From your description you want your scroll area to fill your widget so that you don't have to resize it, hence you need to put the area in a layout applied to said widget.



  • @SGaist
    OK, thanks, I'll have a play.

    All I need to understand is the hierarchy I need. If I started with
    dialog -> vboxlayout1 -> content
    I will now need
    dialog -> vboxlayout2 -> scrollarea ( -> widget ?) -> vboxlayout1 -> content
    Is that right? I'll need a separate vboxlayout from the one I started from, I don't somehow apply the scrollarea to the original vboxlayout?


  • Lifetime Qt Champion

    To make things clearer:

    widget -> vboxlayout1 -> content <- future content of the QScrollArea

    dialog -> vboxlayout2 -> scrollarea <- QScrollArea fitting the "main widget"

    scrollarea -> widget <- finally your widget in the QScrollArea

    See QScrollArea::setWidget



  • @SGaist
    OK, thanks a lot, at least I know what I'm trying to achieve now! :) Will try and report back.



  • @SGaist
    OK, armed with the understanding of what the actual hierarchy should be, I have now modified to outline:

    # self == QDialog
    self.dialogScrollPanel = QVBoxLayout()
    self.setLayout(self.dialogScrollPanel)
    
    scrollArea = QScrollArea(self)
    scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
    scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
    scrollArea.setWidgetResizable(True)
    self.dialogScrollPanel.addWidget(scrollArea)
    
    widget = QWidget()
    scrollArea.setWidget(widget)
    
    self.vertLayout = QVBoxLayout()
    widget.setLayout(self.vertLayout)
    ...
    

    And sure enough my dialog now looks like:
    alt text
    which is just what I was aiming for!

    The one bit I'm left hazy on is when you do or do not need to specify an owner/parent for a layout or widget. My code includes:

    self.dialogScrollPanel = QVBoxLayout()
    self.setLayout(self.dialogScrollPanel)
    
    widget = QWidget()
    scrollArea.setWidget(widget)
    
    self.vertLayout = QVBoxLayout()
    widget.setLayout(self.vertLayout)
    

    In each of these cases the constructor could equally be QVBoxLayout(self) or QWidget(self) and I see the same behaviour. In the code I've inherited it seems sometimes it passes an argument to these and sometimes not. When do I need or not need to pass a widget parent/owner argument when creating a widget or layout?


  • Qt Champions 2016

    @JNBarchan

    Any widget that is not given a parent will become a window.
    So for any widget on a from, you will want to give it a parent.
    However, inserting them into other widgets set the parent.

    For Layouts, its its easier just to assign them to a widget and in that
    way give a parent.

    So in most cases you will just want to give a parent when constructed as
    to make sure they are deleted.



  • @mrjj
    Thanks. I suspect the key is:

    However, inserting them into other widgets set the parent.


  • Lifetime Qt Champion

    I usually follow these rules:

    • When I create layout that should be the "main" layout of a widget, I pass that widget as parent
      Note that's just an habit, if you prefer the setLayout method then go for it, just be consistent all over your code base.
    • All widgets that are put inside a layout will be re-parented appropriately so I don't pass a parent to them.
    • Unless I'm going to manipulate the layout later on I don't make it a member of the class

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.