Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Making widgets touch/stick together in a layout
QtWS25 Last Chance

Making widgets touch/stick together in a layout

Scheduled Pinned Locked Moved Solved General and Desktop
9 Posts 3 Posters 3.1k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • JonBJ Offline
    JonBJ Offline
    JonB
    wrote on last edited by JonB
    #1

    Well, I may have tried this one before, but I'm stuck again....

    • I have a (what I call) a "composite" widget, i.e. it contains several widgets.
    • I want a QListWidget...
    • and immediately under it a row of buttons

    So, a top-level QVBoxLayout containing two "items", the QListWidget followed by a QHBoxLayout on which the buttons will be placed, right?

    class JEditableListCompositeWidget(QtWidgets.QWidget):
        def __init__(self, parent: QtWidgets.QWidget=None):
            super().__init__(parent)
    
            # the top-level QVBoxLayout
            vLayout = QtWidgets.QVBoxLayout()
            self.setLayout(vLayout)
    
            # the QListWidget
            self.lw = QtWidgets.QListWidget()
            self.lw.setFixedHeight(50)
            vLayout.addWidget(self.lw)
    
            # the following QHBoxLayout, with the buttons on it
            hLayout = QtWidgets.QHBoxLayout(self)
            self.btnAdd = QtWidgets.QPushButton("Add")
            hLayout.addWidget(self.btnAdd)
            self.btnDelete = QtWidgets.QPushButton("Delete")
            hLayout.addWidget(self.btnDelete)
            vLayout.addLayout(hLayout)
    

    0_1542986454220_Screenshot from 2018-11-23 15-19-16.png

    No! I do not want that gap between the bottom of the listbox and the top of the buttons, I want the buttons "attached" to just below the listbox. (And note that this time, unlike some previous topic I raised on this issue, I am accepting that the QListWidget has a fixed height, so it does not need grow-space below it.)

    I don't care if I have to introduce an extra level of QBoxLayout if that would solve. It must not matter where I place this whole widget --- maybe inside some QVBoxLayout in the parent dialog --- I do not want stretch introduced between these two rows of controls.

    Now this cannot be so hard, can it...? :)

    1 Reply Last reply
    0
    • JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by JonB
      #9

      So the answer is: to keep widgets together when stretching is involved, and it make such that multiple/composite widgets behave as if you had only added a single widget there, you need explicit stretches above & below, something like:

      vLayout = QVBoxLayout()
      vLayout.addStretch()
      vLayout.addWidget(widget1)
      vLayout.addWidget(widget2)
      vLayout.addStretch()
      
      1 Reply Last reply
      0
      • jazzycamelJ Offline
        jazzycamelJ Offline
        jazzycamel
        wrote on last edited by
        #2

        Try adding a spacer item to the bottom of the layout after the buttons as follows:

        vLayout.addStretch()
        

        This should create a QSpacerItem that fills the available space beneath the buttons and pushes them up to meet the QListWidget.

        For the avoidance of doubt:

        1. All my code samples (C++ or Python) are tested before posting
        2. As of 23/03/20, my Python code is formatted to PEP-8 standards using black from the PSF (https://github.com/psf/black)
        JonBJ 1 Reply Last reply
        4
        • jazzycamelJ jazzycamel

          Try adding a spacer item to the bottom of the layout after the buttons as follows:

          vLayout.addStretch()
          

          This should create a QSpacerItem that fills the available space beneath the buttons and pushes them up to meet the QListWidget.

          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on last edited by JonB
          #3

          @jazzycamel
          Well, that's a pretty good start, 'coz it makes it work for now, so thank you!

          That made the whole widget come at the top of its parent container/layout. So I also put a second vLayout.addStretch() at the start of the QVBoxLayout, above the listbox, to balance the one at the bottom. That centered the location of the composite widget vertically in its container, which seems right.

          But, don't you & I know your solution is really "dirty"? :) I don't want to put stretch at the bottom (or the top), I just want no stretch between the two rows! I sort of wondered if I should put them inside some new, say, QHBoxLayout, which could have a QVBoxLayout inside it to hold the two rows, in the hope that the outer QHBoxLayout would not allow the inner QVBoxLayout to stretch at all, but I haven't tried it...

          1 Reply Last reply
          0
          • jazzycamelJ Offline
            jazzycamelJ Offline
            jazzycamel
            wrote on last edited by
            #4

            @JonB
            I disagree: I don't think its quick and dirty. Qt has to make a default assumption of how to pack the layout and it chooses to evenly distribute the widgets. It then gives you the option to modify that behaviour by adding stretch. If it was packed the way you prefer by default, they would then have to add an option add stretch between all the widgets to evenly distribute them.

            To my mind, your alternative solution of multiple nested layouts feels 'dirty'... I guess its all a matter of opinion and preference :) I'm glad it's working for you either way.

            For the avoidance of doubt:

            1. All my code samples (C++ or Python) are tested before posting
            2. As of 23/03/20, my Python code is formatted to PEP-8 standards using black from the PSF (https://github.com/psf/black)
            JonBJ 1 Reply Last reply
            3
            • jazzycamelJ jazzycamel

              @JonB
              I disagree: I don't think its quick and dirty. Qt has to make a default assumption of how to pack the layout and it chooses to evenly distribute the widgets. It then gives you the option to modify that behaviour by adding stretch. If it was packed the way you prefer by default, they would then have to add an option add stretch between all the widgets to evenly distribute them.

              To my mind, your alternative solution of multiple nested layouts feels 'dirty'... I guess its all a matter of opinion and preference :) I'm glad it's working for you either way.

              JonBJ Offline
              JonBJ Offline
              JonB
              wrote on last edited by JonB
              #5

              @jazzycamel
              No, that's fine, if that is indeed the way I'm supposed to achieve it I'm good with that. Yes, another layer of QBoxLayout to achieve would have been messy.

              Am I right or wrong to think that if I'm going to add a stretch() at the bottom, after the buttons, I should also add one at the top, before the list widget, to "even it up"? Or, is it intended that the stretch should be at the bottom only and not at the top?

              EDIT I think I am right, because if I replace the whole thing by just a QListWidget, placed on a QVBoxLayout in a dialog, the listbox appears at the vertical center of the layout, not at the top which is what it does if I only add your stretch once at the bottom, whereas my two stretches make the composite widget also be in the vertical center. Does that sound correct?

              VRoninV 1 Reply Last reply
              0
              • JonBJ JonB

                @jazzycamel
                No, that's fine, if that is indeed the way I'm supposed to achieve it I'm good with that. Yes, another layer of QBoxLayout to achieve would have been messy.

                Am I right or wrong to think that if I'm going to add a stretch() at the bottom, after the buttons, I should also add one at the top, before the list widget, to "even it up"? Or, is it intended that the stretch should be at the bottom only and not at the top?

                EDIT I think I am right, because if I replace the whole thing by just a QListWidget, placed on a QVBoxLayout in a dialog, the listbox appears at the vertical center of the layout, not at the top which is what it does if I only add your stretch once at the bottom, whereas my two stretches make the composite widget also be in the vertical center. Does that sound correct?

                VRoninV Offline
                VRoninV Offline
                VRonin
                wrote on last edited by
                #6

                @JonB said in Making widgets touch/stick together in a layout:

                Does that sound correct?

                No.
                I'm used to the Qt4 way of layout->addItem(new QSpacerItem(/*...*/)); but stretch probably does exactly the same and is the correct solution

                "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                ~Napoleon Bonaparte

                On a crusade to banish setIndexWidget() from the holy land of Qt

                JonBJ 1 Reply Last reply
                0
                • VRoninV VRonin

                  @JonB said in Making widgets touch/stick together in a layout:

                  Does that sound correct?

                  No.
                  I'm used to the Qt4 way of layout->addItem(new QSpacerItem(/*...*/)); but stretch probably does exactly the same and is the correct solution

                  JonBJ Offline
                  JonBJ Offline
                  JonB
                  wrote on last edited by JonB
                  #7

                  @VRonin
                  I beg your pardon? I believe you have mis-read. I have agreed with @jazzycamel that I need a stretch() at the bottom, after the buttons, then my gap between the listbox and the buttons disappears. That is not the final question. I am saying that done only like that causes the widget's contents, as a whole, to appear at the top of their container, presumably because all the stretch goes to the bottom.

                  I am then saying that if I add another, second stretch() at the top of my composite widget, above the listbox, any stretch gets distributed evenly to the top & bottom (but not middle) of my widget. That makes it place its content in the vertical center of its container.

                  I am asking if that sounds correct, because only this way does my composite behave like if all I had was a listbox in the first place. I have verified that would have appeared vertically centered in the container, not at the top. So I've made my widget behave identically by having a stretch at the top and at the bottom. Doesn't that not sound correct?

                  1 Reply Last reply
                  0
                  • VRoninV Offline
                    VRoninV Offline
                    VRonin
                    wrote on last edited by
                    #8

                    It is up to a certain point. if your widgets are using QSizePolicy::Expanding they will compete for space at the same level as the spacers (streches)

                    "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                    ~Napoleon Bonaparte

                    On a crusade to banish setIndexWidget() from the holy land of Qt

                    1 Reply Last reply
                    0
                    • JonBJ Offline
                      JonBJ Offline
                      JonB
                      wrote on last edited by JonB
                      #9

                      So the answer is: to keep widgets together when stretching is involved, and it make such that multiple/composite widgets behave as if you had only added a single widget there, you need explicit stretches above & below, something like:

                      vLayout = QVBoxLayout()
                      vLayout.addStretch()
                      vLayout.addWidget(widget1)
                      vLayout.addWidget(widget2)
                      vLayout.addStretch()
                      
                      1 Reply Last reply
                      0

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved