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?
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?
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.)
There is no built-in mechanism for this in Quick-Controls-2 combobox (at the time of writing, Qt 5.9), so you have to do it yourself. Something like this...
MyComboBox {
id: comboBox1
sizeToContents: false
model: [ "Banana", "Apple", "ThisIsTheLongestWordThatIHave", "Coconut" ]
}
MyComboBox {
id: comboBox2
anchors.top: comboBox1.bottom
sizeToContents: true
model: [ "Banana", "Apple", "ThisIsTheLongestWordThatIHave", "Coconut" ]
}
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)
}
}
}
Note that if you change the model type from a QML List to a different type, such as C++ QStringList
, QList<QObject*>
or QAbstractListModel
, then you migth need to modify this line textMetrics.text = model[i]
to retrieve the text from the model items in a slightly different way.
ComboBox
is set into a layout, do not forget to add Layout.preferredWidth: width
to the combo box properties. –
Prunella @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
}
}
© 2022 - 2024 — McMap. All rights reserved.
ComboBox
?) How frequently? If the longest word is removed, do you expect theComboBox
to shrink again, or only grow if a longer word is appended? – Split