2

Question

How can I create a QListWidget that has a minimum height but stretches to fill all available space even if the layout already has a stretch component?

Background

I'm using PySide to create dynamic User Interfaces. The components of the interface change depending on the context. My goal is to have a vertical layout as such:

Controls (grid layout with labels)
Stretch
Buttons (Main operation buttons)
StatusBar

The buttons and status bar are just QHBoxLayouts. I'm using a QDialog instead of a QMainWindow since this is often used from within another application such as Maya or Nuke. The dialog is built on the fly and sometimes a QListWidget can be added after the dialog is displayed. I can't predict when to addStretch and when not to.

Trials

I've tried using some of these bits of code to no avail:

# Set the size Policy.
listWidget.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)

# Set a minimum Height
count = min(listBox.count(),12)
bestHeight = count*listBox.sizeHintForRow(0)+5
listBox.setMinimumHeight(bestHeight)

setMinimumHeight() as well as setSizeHint(), I've even tried subclassing the QListWidget to control the sizeHint function. * How to set minimum height of QListWidgetItem? * QListWidget adjust size to content

Example

This is a full example. The QListWidget is not stretching to fill the height. If I remove the addStretch() line, the QListWidget performs as I'd like, but I really want this to be dynamic.

#!/usr/bin/env python
import sys
from PySide import QtCore, QtGui

class myDialog(QtGui.QDialog):
    def __init__(self, parent=None):
        QtGui.QDialog.__init__(self, parent)
        self.setWindowTitle("Testing 123")

        # Declare Layouts.
        self.mainLayout=QtGui.QVBoxLayout()
        self.gridLayout=QtGui.QGridLayout()
        self.buttons = QtGui.QHBoxLayout()
        self.statusBarLayout = QtGui.QHBoxLayout()

        # Set margins.
        self.mainLayout.setContentsMargins(0, 0, 0, 0)
        self.gridLayout.setContentsMargins(4, 4, 4, 4)
        self.buttons.setContentsMargins(0, 0, 0, 0)
        self.statusBarLayout.setContentsMargins(0, 0, 0, 0)

        # Assemble Layouts.
        self.mainLayout.addLayout(self.gridLayout)
        self.mainLayout.addStretch()
        self.mainLayout.addLayout(self.buttons)
        self.mainLayout.addLayout(self.statusBarLayout)

        self.setLayout(self.mainLayout)

        # Fill in Grid Layout.
        row = 0
        self.gridLayout.addWidget(QtGui.QLabel("ComboBox"), row, 0)
        combo = QtGui.QComboBox()
        combo.addItems(['A','B','C','1','2','3'])
        self.gridLayout.addWidget(combo, row, 1)
        row += 1

        self.gridLayout.addWidget(QtGui.QLabel("List"), row, 0)
        listWidget = QtGui.QListWidget()
        listWidget.addItems(['A','B','C','1','2','3'])
        self.gridLayout.addWidget(listWidget, row, 1)
        row += 1

        self.gridLayout.addWidget(QtGui.QLabel("LineEdit"), row, 0)
        self.gridLayout.addWidget(QtGui.QLineEdit(), row, 1)
        row += 1

        # Add some buttons.
        for x in ['One','Two']:
            self.buttons.addWidget(QtGui.QPushButton(x))

        # Add the psuedo status bar.
        self.statusBar = QtGui.QStatusBar()
        self.statusBarLayout.addWidget(self.statusBar, 4 )

        self.statusBar.showMessage("Hello World")

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    dialog = myDialog()
    sys.exit(dialog.exec_())
Community
  • 1
  • 1
Krets
  • 349
  • 2
  • 13
  • Why are you adding a stretch? –  Mar 27 '13 at 22:27
  • Often my layout won't include the QListWidget. When this happens I want the stretch to keep the button layout and statusbar layout pushed to the bottom. If it were possible to add and remove stretch on the fly, this would solve my problem. – Krets Mar 27 '13 at 22:47

2 Answers2

2

I've figured it out. I need to increase the stretch factor of the gridLayout when I add it to the mainLayout. It has nothing to do with the QListWidget.

Here's the short of it:

self.mainLayout.addLayout(self.gridLayout, 1) # stretch factor > 0
self.mainLayout.addStretch(0) # Default is 0
Krets
  • 349
  • 2
  • 13
1

If you know the index of the spacer use the takeAt ( int index ) method to remove it, or else use a QSpacerItem instead, something like:

self.spacerItem = QtGui.QSpacerItem(
    20, 40,
    QtGui.QSizePolicy.Minimum,
    QtGui.QSizePolicy.Expanding
)
self.layout.addItem(self.spacerItem)

Then remove it with removeItem ( QLayoutItem * item ):

self.layout.removeItem(self.spacerItem)
  • 1
    Thanks for taking the time to answer. This would have worked well. As I pointed out in my solution. I was not creating my layout correctly. Now that I am setting a good stretch factor everything works great. – Krets Mar 28 '13 at 01:11