How do I set the ComboBox width to fit the largest item

Viewed 6537

I would like that my ComboBox has to adapt its width to the longest String Item of my list.

Code Example:

ComboBox {
    model: [ "Banana", "Apple", "ThisIsTheLongestWordThatIHave,"Coconut" ]
}

Any idea of how to do it?

5 Answers

As of Qt 6, this is now possible by setting the ComboBox's implicitContentWidthPolicy to either ComboBox.WidestText , which will update whenever the model changes, or ComboBox.WidestTextWhenCompleted, which will check just once, when the ComboBox is loaded. (Keep in mind that the latter might not work as expected if the model isn't already available at the instant the ComboBox is loaded.)

@Mark Ch - MyComboBox doesn't work with Controls 2; the width of the indicator is not taken into account so it is too narrow if the indicator has any width.

It worked for me by replacing the assignment for width: with the following:

width: sizeToContents
             ? (modelWidth + leftPadding + contentItem.leftPadding
                           + rightPadding + contentItem.rightPadding)
             : implicitWidth

Here's a different approach which is less dependent on internals, works with any kind of model, and with alternate ComboBox styles e.g. "material":

The idea is to just set currentItem to each possible value and let the ComboBox internals do their thing; then observe the resulting widths. ComboBox.contentItem is a TextField, and TextField.contentWidth has what we want. We don't have to know how to iterate the model or emulate what a delegate might do to change formatting. The desired ComboBox width is the max of those contentWidths, plus padding and indicator width.

The calculation can not be directly bound to width because a binding loop would occur. Instead, width is calculated and set statically when the onCompleted signal occurs.

Note: The following code doesn't yet handle dynamically updated models. I may update this post later...

USAGE:

import QtQuick 2.9
import QtQuick.Controls 2.2
import "ComboBoxHacks.js" as CBH
...
ComboBox {
  id: myCB
  Component.onCompleted: width = CBH.calcComboBoxImplicitWidth(myCB)
  ...
}

And here is the javascript code:

/* ComboBoxHacks.js */
function calcComboBoxImplicitWidth(cb) {
  var widest = 0
  if (cb.count===0) return cb.width
  var originalCI = cb.currentIndex
  if (originalCI < 0) return cb.width // currentIndex →  deleted item
  do {
    widest = Math.max(widest, cb.contentItem.contentWidth)
    cb.currentIndex = (cb.currentIndex + 1) % cb.count
  } while(cb.currentIndex !== originalCI)

  return widest + cb.contentItem.leftPadding + cb.contentItem.rightPadding
                + cb.indicator.width
}

You just need to update the minimumWidth when the model changes.

import QtQml 2.12
import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.12

ComboBox {
    id: root

    onModelChanged: {
        var _maxWidth = 0
        for(var i = 0; i < model.length; i++){
            // TextMetrics does not work with Material Style
            _maxWidth = Math.max((model[i].length+1)*Qt.application.font.pixelSize, _maxWidth)
        }
        Layout.minimumWidth = _maxWidth + implicitIndicatorWidth + leftPadding + rightPadding
    }
}
Related