PDA

View Full Version : QML 'Custom Menu' option moving upwards



ddonate
24th November 2016, 11:32
Hi,

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 dinamically (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'), since main window height depends on this Rect2 visible height...

I have it working, but it flickes 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?

Thanks


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
}
}

anda_skoa
24th November 2016, 13:41
Are you triggering the animation with a Behavior element?

Cheers,
_

ddonate
24th November 2016, 15:31
I have tried now with Behaviour's in each element, but the effect is still really bad...

I added
Behavior on height { NumberAnimation { duration: 500 } }
in every Rectangle
and
Behavior on y { NumberAnimation { duration: 500 } }
in the main window

Cheers

anda_skoa
24th November 2016, 15:51
Does it help if you only do one of these? What about each combination of two?

Cheers,
_

ddonate
24th November 2016, 16:34
I'm afraid I don't understand you...

anda_skoa
25th November 2016, 10:56
If you have only one of these animations, does it behave well?
If you try different combinations of two of these animations, are there combinations that work?

Cheers,
_

ddonate
25th November 2016, 13:02
I have tried different options but no sucess, the bottom (fixed) menu1 always moves (although smoothly with animations). And this menu should be always at the bottom, while menu2 is the one that moves up (increasing the main window size, but without affecting menu1).

Thanks

anda_skoa
25th November 2016, 14:04
You could try using a ListView instead of two moving elements and adding/removing an element to/from the model when needed, using the view's add/remove transitions handle the animation aspect.

Cheers,
_

ddonate
25th November 2016, 14:35
I thought about that option, but when adding/removing an element from the Lisview (from the model), the main window will not be increased downwards?

anda_skoa
26th November 2016, 09:36
You could still do that with an animation.

Cheers,
_

ddonate
29th November 2016, 12:08
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 (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


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);
}
}
}

anda_skoa
29th November 2016, 12:24
In your first attempt you had both rectangles animated. So only one of them actually is?

Cheers,
_

anda_skoa
29th November 2016, 12:25
In your first attempt you had both rectangles animated. So only one of them actually is?

Cheers,
_

ddonate
29th November 2016, 12:32
Having 2 rectangles was only an option I thought to achieve my target, and I tried to animate both to keep the bottom RECT at the bottom side of the main window, while the upper RECT moves up (so the "hidden" RECT appears in the 2nd position)

But maybe there is an easier way to get what I need (maybe I am not explaining properly what I need). Now my code is simpler, with the same (bad) result: the bottom RECT moves down, since the main window (in this case a ListView) increases its height downwards by default.