How to set ComboBox width to fit the largest item

I wish mine ComboBox

had to adapt mine width

to the longest of String Item

my list.

Sample code:

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

      

Any idea how to do this?

+5


source to share


4 answers


There is no built-in mechanism in the Quick-Controls-2 assembly (at the time of writing, Qt 5.9), so you need to do it yourself. Something like that...

main.qml

MyComboBox {
    id: comboBox1
    sizeToContents: false
    model: [ "Banana", "Apple", "ThisIsTheLongestWordThatIHave", "Coconut" ]
}

MyComboBox {
    id: comboBox2
    anchors.top: comboBox1.bottom
    sizeToContents: true
    model: [ "Banana", "Apple", "ThisIsTheLongestWordThatIHave", "Coconut" ]
}

      



MyComboBox.qml

ComboBox {
    id: control

    property bool sizeToContents
    property int modelWidth

    width: (sizeToContents) ? modelWidth + 2*leftPadding + 2*rightPadding : implicitWidth

    delegate: ItemDelegate {
        width: control.width
        text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole] : model[control.textRole]) : modelData
        font.weight: control.currentIndex === index ? Font.DemiBold : Font.Normal
        font.family: control.font.family
        font.pointSize: control.font.pointSize
        highlighted: control.highlightedIndex === index
        hoverEnabled: control.hoverEnabled
    }

    TextMetrics {
        id: textMetrics
    }

    onModelChanged: {
        textMetrics.font = control.font
        for(var i = 0; i < model.length; i++){
            textMetrics.text = model[i]
            modelWidth = Math.max(textMetrics.width, modelWidth)
        }
    }
}

      

Please note that if you change the model type from the QML list to another type, for example C ++ QStringList

, QList<QObject*>

or QAbstractListModel

, then you need to change this line textMetrics.text = model[i]

to get the text from the model elements in a slightly different way.

+4


source


@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.

This worked for me, replacing the assignment for the width with the following:



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

      

+1


source


Here's a different approach, which is less dependent on internals, works with any model and with alternative ComboBox styles such as "material":

The idea is to simply set currentItem

for every possible value and let the ComboBox internals do their thing; then respect the resulting width. ComboBox.contentItem

is TextField

, but TextField.contentWidth

has what we want. We don't need to know how to iterate over the model or emulate what it can do delegate

to change formatting. The desired ComboBox width is the maximum of these contentWidths, plus padding and indicator width.

The computation cannot be directly linked to width

because the binding cycle will take place. Instead, the width is computed and set statically when the onCompleted signal occurs.

Note. The following code does not yet handle dynamically updated models. I can update this post later ...

USING:

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
}

      

0


source


You just need to update the minimum width 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
    }
}

      

0


source







All Articles