0
votes

I am trying to create a "menu" in QML with custom data in each option For requirements of my application, I need to show it loading the QML file dynamically (Qt.createComponent). What I need is to show some fixed options in the bottom part, and when clicked the top one, another options appear below this top option, which keeps in the top A simple example. I have this menu:

Option 4
Option 2
Option 1

And when clicked in Option 4, the menu changes to

Option 4
Option 3
Option 2
Option 1

So Option 4 is moved upwards and Option 3 appears.

I would like to have a 'shadow' around all my menu (I added a DropShadow component for that purpose).

I have this simple test code, where I have a main Rectangle (to be surrounded by the shadow), and 2 Rectangles inside. Rect1 for the fixed part (Option 1, Option 2), and Rect2 for the 'movable' part (Option 3, Option 4). Rect2 is behind Rect1 (z: -1), and located to have only Option 4 visible, above Option 2. When clicked Option 4, Rect2 is moved upwards and all options are visible.

To achieve that, I have to update Rect2 visible height, and main window position (y value), since main window height depends on this Rect2 visible height.

I have it working, but it flicks a lot since 2 variables changes ('fixed panel' is moved upwards and back).

I have also tried with a ParallelAnimation for 2 values, but no success.

Any idea to have this menu with a smooth movement?

Main.qml:

import QtQuick 2.0

Rectangle 
{
    id: window

    property variant win: undefined;
    Component.onCompleted: 
   {
        var component = Qt.createComponent("TestMenu.qml");
        win = component.createObject(window, {"x": 500, "y": 500});
        win.show();
    }
}

TestMenu.qml:

import QtQuick 2.0
import QtQuick.Window 2.1
import QtGraphicalEffects 1.0

Window {
    id: window
    flags: Qt.Tool | Qt.FramelessWindowHint
    height: panel.height
    color: "transparent"

    property int radiusShadow: 20
    property int iOptionHeight: 30

    Rectangle {
        id: panel
        anchors { centerIn: parent}

        height: menu1.height + menu2.heightVisible + 2*radiusShadow
        width: window.width - 2*radiusShadow
        color: "transparent"

        Rectangle {
            id: menu1

            anchors { bottom: parent.bottom; bottomMargin: radiusShadow }
            width: parent.width
            height: column1.children.length * iOptionHeight

            Column {
                id: column1
                anchors.fill: parent
                Rectangle {
                    color: "red";
                    Text { text: qsTr("option 2") }
                    height: iOptionHeight;  width: parent.width
                }
                Rectangle {
                    color: "green";
                    Text { text: qsTr("option 1") }

                    height: iOptionHeight;  width: parent.width
                }
            }
        }

        Rectangle {
            id: menu2

            property int heightVisible: iOptionHeight

            anchors { top: parent.top; topMargin: radiusShadow; left: menu1.left }
            width: parent.width
            height: column2.children.length * iOptionHeight

            z: -1

            Column {
                id: column2

                anchors.fill: parent
                Rectangle {
                    id: blue
                    property bool bOpen: false
                    color: "blue";
                    height: iOptionHeight;  width: parent.width
                    Text { text: qsTr("option 4") }

                    MouseArea {
                        anchors.fill: parent
                        onClicked: {
                            blue.bOpen = !blue.bOpen;
                            panel.showHideMenu2(blue.bOpen);
                        }
                    }
                }
                Rectangle {
                    color: "pink";
                    Text { text: qsTr("option 3") }
                    height: iOptionHeight;  width: parent.width
                }
            }
        }

        function showHideMenu2(bShow)
        {
            if (bShow)
            {
                window.y -= iOptionHeight
                menu2.heightVisible += iOptionHeight;
            }
            else
            {
                window.y += iOptionHeight
                menu2.heightVisible -= iOptionHeight;
            }
        }
    }

    DropShadow {
        id: dropShadow
        visible: true
        anchors.fill: panel
        radius: radiusShadow
        samples: 24
        color: "#40000000"
        source: panel
    }
}
2

2 Answers

0
votes

As a quick answer for your question, you can get what you want using Behavior animation for a property change.

Here, Behavior animation will be used on y (position) change of your window, and for height change of respective rectangles.

Here is the patch for your code I recommend you to apply to see smooth movement:

@@ -10,6 +10,9 @@

     property int radiusShadow: 20
     property int iOptionHeight: 30
+    property int animationDuration: 500 // ms
+
+    Behavior on y { NumberAnimation { duration: window.animationDuration } }

     Rectangle {
         id: panel
@@ -18,6 +21,7 @@
         height: menu1.height + menu2.heightVisible + 2*radiusShadow
         width: window.width - 2*radiusShadow
         color: "transparent"
+        Behavior on height { NumberAnimation { duration: window.animationDuration } }

         Rectangle {
             id: menu1
@@ -25,6 +29,7 @@
             anchors { bottom: parent.bottom; bottomMargin: radiusShadow }
             width: parent.width
             height: column1.children.length * iOptionHeight
+            Behavior on height { NumberAnimation { duration: window.animationDuration } }

             Column {
                 id: column1
@@ -52,6 +57,8 @@
             width: parent.width
             height: column2.children.length * iOptionHeight

+            Behavior on height { NumberAnimation { duration: window.animationDuration } }
+
             z: -1

             Column {
@@ -64,6 +71,7 @@
                     color: "blue";
                     height: iOptionHeight;  width: parent.width
                     Text { text: qsTr("option 4") }
+                    Behavior on height { NumberAnimation { duration: window.animationDuration } }

                     MouseArea {
                         anchors.fill: parent
@@ -77,6 +85,7 @@
                     color: "pink";
                     Text { text: qsTr("option 3") }
                     height: iOptionHeight;  width: parent.width
+                    Behavior on height { NumberAnimation { duration: window.animationDuration } }
                 }
             }
         }
@@ -105,4 +114,4 @@
         color: "#40000000"
         source: panel
     }
-}+}
0
votes

I have tried with a model and a ListView (code is simpler now), but I don't know where and how insert an 'Animation' or a 'Behaviour' to achieve my target, if it is possible to do it (I have tried several options with no success...)

The expected effect is that the 1st rectangle moves up when the 2nd appears, so the bottom one keeps in its position (at bottom). But the default behaviour when I add an element to the model is that the list increased the height downwards

Maybe anyone could help...

My code:

import QtQuick 2.0
import QtQuick.Controls 1.4

Rectangle {
    id: rootItem
    width: 400
    height: list.height

    ListModel {
        id: modelRects
        ListElement {  rectColor: "green" }
        ListElement {  rectColor: "orange" }
    }

    ListView {
        id: list
        height: modelRects.count * 30
        model: modelRects
        delegate: Rectangle {
                id: delegate
                height: 30
                width: rootItem.width
                color: rectColor

                MouseArea {
                    anchors.fill: parent
                    onClicked: onRectClicked(index);
                }
            }
        }

    function onRectClicked(index)
    {
        if (index == 0)
        {
            if (modelRects.count == 2)
                modelRects.insert(1, {"idRect": 2, "rectColor": "red"});
            else
                modelRects.remove(1, 1);
        }
    }
}