0

Is there a QML type to build an unfolding menu like that:

state1:

state1

state2:

state2

Or do I have to somehow engineer this type by combining other types and logic?

Edit:

This is how I'vew done it. There are of course improvements possible, e.g.anchoring the ScrollView of the tables to the header row, using a Repeater intead of creating objects, modularize the components into seperate files, etc.:

import QtQuick 2.7
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.4
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.1
import QtQuick.Window 2.2

ApplicationWindow {
    id: rootWindow

    visible: true
    width: 320
    height: 320

    Rectangle {
        id:base
        anchors.fill: parent
        color: "#FFFFFFFF"
        property var numOfInputs

        property var inputcomp
        signal currFullInputChanged();

        function start() {
            currFullInputChanged()
        }

        Window {

            id: win
            x: base.anchors.rightMargin
            width: 200
            height: 200
            visible: true

            MouseArea {
                id: area
                anchors.fill: parent
                property int count: 0

                onClicked: {

                    inputmod.append({"Key_1": count, "Key_2": count+1})
                    ++count;

                    base.start()
                }
            }
        }

        Component.onCompleted: {

            win.show()
        }


        onCurrFullInputChanged: {

            if(typeof inputcomp !== "undefined")
                inputcomp.destroy()

            numOfInputs = inputmod.count
            inputcomp = inputComponent.createObject(this, {"inputRows": numOfInputs})
        }



        ListModel {
            id: inputmod
        }

        Component {
            id: inputComponent

            Column {
                id: clTop
                anchors.fill: parent
                width: parent.width
                height: parent.height
                spacing: 1
                property int inputRows
                property int lastIndex: -1
                property var objs: []

                Component {
                    id: inputitem

                    Item {
                        id:item_
                        width: parent.parent.width


                        height: parent.parent.height/12

                        property string clickedColor: "#B4D0B4"

                        property int currIndex

                    Rectangle {
                        id: rectinfo

                        anchors.top: parent.top
                        anchors.left: parent.left
                        anchors.right: parent.right
                        height: rectexpand.open === 0 ? parent.height : parent.height/4
                        border.width: 1
                        border.color: "#E4EEDA"
                        radius: 2
                        color: baseColor
                        property string baseColor: "#FDFFF9"


                        Text {
                            anchors.top: parent.top
                            anchors.left: parent.left
                            padding: 5
                            width: parent.width/2
                            height: parent.height/2
                            fontSizeMode: Text.Fit
                            text: "Input " + parseInt(parent.parent.currIndex + 1)
                            horizontalAlignment: Text.AlignLeft
                            verticalAlignment: Text.AlignTop
                            wrapMode: Text.WordWrap
                            elide: Text.ElideRight
                            font.family: "Helvetica"
                            font.bold: true

                        }

                        MouseArea {
                            anchors.fill: parent
                            hoverEnabled: true

                            onClicked: {

                                rectexpand.open = rectexpand.open === 0 ? 1 : 0
                                item_.height = Qt.binding(function() { return rectexpand.open === 0 ? clTop.height*1/12 : clTop.height*4/12} )

                                var currIndex = parent.parent.currIndex

                               if(clTop.lastIndex > -1) {
                                    var lastItem = clTop.objs[clTop.lastIndex];
                                    lastItem.children[0].color = lastItem.children[0].baseColor;
                                    lastItem.children[1].color = lastItem.children[1].baseColor;
                                    lastItem.children[0].opacity = 1
                                    lastItem.children[1].opacity = 1
                                }

                                var currItem = clTop.objs[currIndex];
                                currItem.children[0].color = parent.parent.clickedColor
                                currItem.children[1].color = parent.parent.clickedColor
                                currItem.children[0].opacity = 0.5
                                currItem.children[1].opacity = 0.5

                                clTop.lastIndex = parent.parent.currIndex
                            }
                        }
                   }

                    Rectangle {
                        id: rectexpand
                        anchors {top: rectinfo.bottom; left: parent.left; bottom: parent.bottom; right: parent.right}
                        border.width: 1
                        radius: 0
                        border.color: "grey"
                        property string baseColor: "white"
                        property int open: 0

                        onOpenChanged: {

                            if(open === 1)
                               tabloader.sourceComponent = view;
                            else
                               tabloader.sourceComponent = undefined;
                        }

                        Component {
                            id: del


                            Item {

                                anchors.left: parent !== null ? parent.left : undefined
                                anchors.right: parent !== null ? parent.right : undefined

                                TextInput {
                                    id: textinput
                                    anchors.margins: 4
                                    anchors.left: parent !== null ? parent.left : undefined
                                    anchors.verticalCenter: parent !== null ? parent.verticalCenter : undefined
                                    text: styleData.value
                                    color:  styleData.textColor
                                }
                            }
                        }

                        Component {
                            id: view


                            TableView {
                                anchors.fill: parent
                                itemDelegate: del
                                model: inputmod


                                TableViewColumn {
                                    id: col1
                                    role: "Key_1"
                                    title: "Key 1"
                                    width: parent !== null ? parent.width/2 - 2 : 0
                                }
                                TableViewColumn {
                                    id: col2
                                    role: "Key_2"
                                    title: "Key 2"
                                    width: parent !== null ? parent.width/2 - 2 : 0
                                }
                            }
                            }

                        Loader {
                            id: tabloader
                            anchors.fill: parent
                        }
                        }
                   }

                }

                Component.onCompleted: {

                    for(var i=0; i<inputRows; ++i) {

                        objs.push(inputitem.createObject(this, {"currIndex": i}))
                    }
                }

                Component.onDestruction: {

                    for(var i=0; i<inputRows; ++i) {

                        objs[i].destroy()
                    }
                }
            }
        }
    }
}
tanius
  • 14,003
  • 3
  • 51
  • 63
FloriHe
  • 73
  • 7
  • I recently did something pretty much identical, you only have to do your styling: https://stackoverflow.com/a/43094660/991484 And I don't recall QML offering something out of the box, but then again, I am not actively using stock qml components either. – dtech Oct 16 '17 at 09:56
  • Unfortunately, your example is neither complete nor verifiable. – FloriHe Oct 16 '17 at 10:24
  • What do you mean? It even has an animation showing how the code works... – dtech Oct 16 '17 at 10:26
  • No import statements. AccItem not defined. – FloriHe Oct 16 '17 at 10:27
  • See that `// AccItem.qml` in the first line of the example? That means you should put that in an `AccItem.qml` file in your project. As it is a project file, no import statements are needed. For the actual code to run, you only need the default `import QtQuick 2.whatever`. – dtech Oct 16 '17 at 10:30
  • Yep, so you should have made two separate code-snippets, for each file. As the import statements are missing and Acc.qml isn't included in a root win, so that the application can be run, it isn't 'cv' . Don't get me wrong, your example is working fine, it's just that people here are very fast in complaining and linking to the 'mcve' page. – FloriHe Oct 16 '17 at 10:46
  • 1
    My example contains the entire implementation. It is presumed that users know the most basic things about programming with a particular language. This site is about solving programming questions, not about spoon-feeding lazies who can't be bothered with common sense and trivialities. The full working code is a requirement for when **you are asking** the question in order to identify the problem. Now if someone is a lazy spoiled crybaby, that is not my problem, and it is not something that should be encouraged/nurtured, as it will be a huge detriment to that individual's programming career. – dtech Oct 16 '17 at 10:54
  • Thanks, I'll copy/paste that, when needed. – FloriHe Oct 16 '17 at 11:01

1 Answers1

1

Apperently QML still does not have enough usefull Control types like such kind of menus. But it has enought basic components to create your own ControlsWidgets/whatsoever.

To make such menu you can use

  1. ListView QML Component with custom delegate for items. Here is an example/tutorial And here is Expanding Delegates in Qt docs
  2. Use Menu Control from QtQuick.Controls 2 and customize MenuItem like described here
Xplatforms
  • 2,102
  • 17
  • 26