Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to limit the size of drop-down of a ComboBox in QML

I am using a ComboBox in QML and when populated with a lot of data it exceeds my main windows bottom boarder. From googling I have learned that the drop-down list of a ComboBox is put on top of the current application window and therefore it does not respect its boundaries.

Ideally I would want the ComboBox to never exceed the main applications boundary, but I can not find any property in the documentation.

A different approach would be to limit the number of visible items of the drop-down list so that it do not exceed the window limits for a given window geometry. I was not able to find this in the documentation either and I have run out of ideas.

like image 335
uniquenamehere Avatar asked Oct 15 '25 04:10

uniquenamehere


2 Answers

Take a look to the ComboBox source code, the popup is of a Menu type and it doesn't have any property to limit its size. Moreover, the z property of the Menu is infinite, i.e. it's always on top.

If you Find no way but to use the ComboBox of Qt you can create two models one for visual purpose, I will call it visual model, you will show it in your ComboBox and the complete one , it will be the reference model. Items count in your VisualModel wil be equal to some int property maximumComboBoxItemsCount that you declare . you'll need o find a way that onHovered find the index under the mouse in the visualmodel if it's === to maximumComboBoxIemsCount you do visualModel.remove(0) et visualModel.add(referenceModel.get(maximum.. + 1) and you'll need another property minimumComboBoxIemsCount, same logic but for Scroll Up , I dont know if it will work. but it's an idea

I think there is no solution using the built-in component and you should create your own comboBox. You can start from the following code.

ComboBox.qml

import QtQuick 2.0 

Item {
    id: comboBox

    property string initialText
    property int maxHeight
    property int selectedItem:0
    property variant listModel
    signal expanded
    signal closed
    //    signal sgnSelectedChoice(var choice)
    width: 100
    height: 40
    ComboBoxButton {
        id: comboBoxButton
        width: comboBox.width
        height: 40
        borderColor: "#fff"
        radius: 10
        margin: 5
        borderWidth: 2
        text: initialText
        textSize: 12

        onClicked: {
            if (listView.height == 0)
            {
                listView.height = Math.min(maxHeight, listModel.count*comboBoxButton.height)
                comboBox.expanded()
                source = "qrc:/Images/iconUp.png"
            }
            else
            {
                listView.height = 0
                comboBox.closed()
                source = "qrc:/Images/iconDown.png"
            }
        }
    }

    Component {
        id: comboBoxDelegate

        Rectangle {
            id: delegateRectangle
            width: comboBoxButton.width
            height: comboBoxButton.height
            color: "#00000000"
            radius: comboBoxButton.radius
            border.width: comboBoxButton.borderWidth
            border.color: comboBoxButton.borderColor



            Text {
                color: index == listView.currentIndex ? "#ffff00" : "#ffffff"
                anchors.centerIn: parent
                anchors.margins: 3
                font.pixelSize: 12
                text: value
                font.bold: true
            }


            MouseArea {
                anchors.fill: parent

                onClicked: {
                    listView.height = 0
                    listView.currentIndex = index
                    comboBox.selectedItem = index
                    tools.writePersistence(index,5)
                    comboBoxButton.text = value
                    comboBox.closed()
                }
            }
        }
    }

    ListView {
        id: listView
        anchors.top: comboBoxButton.bottom
        anchors.left: comboBoxButton.left
        width: parent.width
        height: 0
        clip: true
        model: listModel
        delegate: comboBoxDelegate
        currentIndex: selectedItem
    }
    onClosed:  comboBoxButton.source = "qrc:/Images/iconDown.png"
    Component.onCompleted: {
        var cacheChoice = tools.getPersistence(5);
        listView.currentIndex = tools.toInt(cacheChoice)
        selectedItem = listView.currentIndex
        comboBoxButton.text = cacheModel.get(selectedItem).value
    }
}

ComboBoxButton.qml

    import QtQuick 2.0 

Item {
    id: container
    signal clicked
    property string text
    property alias source : iconDownUp.source
    property string color: "#ffffff"
    property int textSize: 12
    property string borderColor: "#00000000"
    property int borderWidth: 0
    property int radius: 0
    property int margin: 0

    Rectangle {
        id: buttonRectangle
        anchors.fill: parent
        color: "#00000000"
        radius: container.radius
        border.width: container.borderWidth
        border.color: container.borderColor

        Image {
            id: image
            anchors.fill:  parent
            source: "qrc:/Images/buttonBackground.png"

            Image {
                id: iconDownUp
                source: "qrc:/Images/iconDown.png"
                sourceSize.height:20
                sourceSize.width: 20
                anchors.verticalCenter: parent.verticalCenter
            }
        }

        Text {
            id:label
            color: container.color
            anchors.centerIn: parent
            font.pixelSize: 10
            text: container.text
            font.bold: true
        }

        MouseArea {
            id: mouseArea;
            anchors.fill: parent
            onClicked: {
                container.clicked()
                buttonRectangle.state = "pressed"
                startTimer.start()
            }
        }
        Timer{
            id:startTimer
            interval: 200
            running: false;
            repeat: false
            onTriggered: buttonRectangle.state = ""
        }
        states: State {
            name: "pressed"
            when: mouseArea.pressed
            PropertyChanges { target: image; scale: 0.7 }
            PropertyChanges { target: label; scale: 0.7 }
        }

        transitions: Transition {
            NumberAnimation { properties: "scale"; duration: 200; easing.type: Easing.InOutQuad }
        }
    }
}

I've used it in some software of mine, hence it is possible that It could not work "out of the box". I use it like this:

ComboBox{
    id:cacheChoice
    initialText: "None"
    anchors.top: baseContainer.top
    anchors.topMargin: 2
    anchors.right: baseContainer.right
    maxHeight: 500
    listModel: cacheModel

    onExpanded: {
        cacheChoice.height = 500
    }

    onClosed: {
        cacheChoice.height = 20
    }
}
like image 55
Mido Avatar answered Oct 17 '25 22:10

Mido


In case you are working with ComboBox from Qt Quick Controls 2, here's the source code for it:

https://github.com/qt/qtquickcontrols2/blob/5.12/src/imports/controls/ComboBox.qml

Based on that, this override of the behavior works to limit the height to something reasonable:

    myComboBox.popup.contentItem.implicitHeight = Qt.binding(function () {
        return Math.min(250, myComboBox.popup.contentItem.contentHeight);
    });
like image 21
David K. Hess Avatar answered Oct 17 '25 23:10

David K. Hess