QML Transition Animation using Animators and PropertyAnimation Combined - qt

Facing some issue using QML Animatiors in state Transition animations. Here is my working sample Code. In this sample if I decide not to provide "from" Attribute for the OpacityAnimator( reason is i wanted it to consider the current property value) the animator is not animating the property.
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtQuick.Window 2.12
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
property bool isOpen: false
Button {
anchors.centerIn: parent
text: "Fade Animation Open Layer "
onClicked: {
isOpen = true;
overlay.state = "open";
}
}
Rectangle {
id: overlay
anchors.fill: parent
color: "green"
visible: isOpen
opacity: 0
Button {
anchors.centerIn: parent
text: "Close Overlay"
onClicked: {
overlay.state = "close"
}
}
state: "close"
states: [
State {
name: "hidden"
},
State {
name: "visible"
}
]
transitions: [
Transition {
from: "close"
to: "open"
OpacityAnimator {
target: overlay
from: 0.0
to: 1.0
duration: 600
easing.type: Easing.OutCubic
}
},
Transition {
from: "open"
to: "close"
SequentialAnimation {
OpacityAnimator {
target: overlay
//from: overlay.opacity
to: 0.0
duration: 600
easing.type: Easing.OutCubic
}
ScriptAction {
script: {
isOpen = false;
}
}
}
}
]
}
}
If i use PropertyAnimation instead, the fade effect works absolutely fine. So I just digged in to the Animator Code to and found out the below snippet from the apply function of qquickanimator.cpp and assume it means if "from" not specified it is supposed to fetch it from the target's property value and a comment Claims the magic line works like PropertyAnimation. But it is not working this way
if (isFromDefined)
job->setFrom(from);
else if (action.fromValue.isValid())
job->setFrom(action.fromValue.toReal());
else
job->setFrom(action.property.read().toReal());
// This magic line is in sync with what PropertyAnimation does
// and prevents the animation to end up in the "completeList"
// which forces action.toValue to be written directly to
// the item when a transition is cancelled.
action.fromValue = action.toValue;
So my Questions are:
Is it a Bug in the Qt Animator or am I missing something here?
Is it ok to combine PropertyAnimation and Animators(Opacity,Scale) in a Grouped animation(Sequential or Parallel) for a state Transition provided Animators scope is Scene graph and for PropertyAnimation it's the target object

See this comment in the documentation for the from property of Animator:
If the Animator is defined within a Transition or Behavior, this value defaults to the value defined in the starting state of the Transition, or the current value of the property at the moment the Behavior is triggered.
I think this means it will use the to value of 1.0 from the open state instead of the current value on the target. Seems like the state machinery is tracking and using how the transitions left things instead of current values.
Your from: overlay.opacity should workaround that behavior?

Related

Why my animations works in a strange way?

I have write a simple animation demo,but the animation work in a strange way.
The Code
import QtQuick 2.5
import QtQuick.Controls 2.12
ApplicationWindow {
visible: true
width: 480
height: 680
id: root
Rectangle {
id: rect
width: 200
height: 200
color: "blue"
anchors.centerIn: parent
states: State {
name: "A"
when: mouseArea.pressed
PropertyChanges {target: rect; color:"red"; }
PropertyChanges {target: rect; width: rect.width + 100}
PropertyChanges {target: rect; rotation: 720}
}
transitions: Transition {
ColorAnimation {duration: 1000}
NumberAnimation {duration: 1000}
RotationAnimation {duration: 1000}
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
}
}
Q1: When mouse press and hold, I want the rectange width increase 100 every time,but my code seems not work?
Q2: If the width assign a const value(eg 100), the NumberAnimation seems not work, the width change immediately?
Q3:The RotationAnimation not rotate 720, it rotate exceed 720?
Currently, I am not familiar with js&qml, Hope Good Man(Woman) can help me.
Q1: You shouldn't bind rect.width to itself. That causes a binding loop. Either use a constant value or come up with some way outside of rect to keep track of what size you want the rect to be.
Q2: You need to tell the NumberAnimation which property to animate on. In this case it's "width".
Q3: 720 degrees means twice all the way around. That's exactly what I'm seeing when I test it, so I think it's working correctly.
The code below works for me.
Rectangle {
id: rect
width: 200
height: 200
color: "blue"
anchors.centerIn: parent
states: State {
name: "A"
when: mouseArea.pressed
PropertyChanges {target: rect; color:"red"; }
PropertyChanges {target: rect; width: 300} // Fixed value
PropertyChanges {target: rect; rotation: 720}
}
transitions: Transition {
ColorAnimation {duration: 1000}
NumberAnimation {property: "width"; duration: 1000} // Specify property
RotationAnimation {duration: 1000}
}
}
In addition to the answer from JarMan, I think you want to define a onPressed handler in the MouseArea, where you assign a new value to the width of the rect (note the difference between "binding" and "assigning"):
MouseArea {
id: mouseArea
anchors.fill: parent
onPressed: rect.width += 100
}
To clarify why that PropertyChange on width didn't work: as long as State "A" is active (thus during the mouse press), the PropertyChange overwrites the binding in the original Rectangle code, and you are defining it as a binding, meaning during the "A" state, the width is bound to itself (the binding loop that JarMan writes about). When state "A" is not active anymore, it will return to width: 300 (which is basically also a binding, albeit being constant).
When you use the above onPressed handler, the width property will loose it's binding and become fixed to the value assigned to it. Note: you can make it bound again by using Qt.binding or temporarily by using another PropertyChanges from a State

Qml StackView Push Transition is not working

I'm making an application with Qt and QML ( version 5.10 ) and using Qt.QuickControl 1.5.
I'm facing a problem with the StackView Transition:
Whenever I push an Item I make a simple Sliding Transition, the enterItem slides in and the exitItem slides out.
StackView {
id: stackView
anchors.fill: parent
focus: true
delegate: StackViewDelegate {
pushTransition: StackViewTransition {
PropertyAnimation {
target: exitItem
property: "x"
from: 0
to: exitItem.width
}
PropertyAnimation {
target: enterItem
property: "x"
from: -enterItem.width
to: 0
}
}
}
}
It's really simple. The problem is that when I push an Object in the StackView the transition is not happening. BUT when I pop the Transition I see the transition.
I create the objects for the StackView dynamically like
stackView.push(Qt.createComponent(_someurl_).createObject());
I cannot understand what the problem is.

How to setup my button component to open a window

Here is the code of the window I wanna be opened in file PopUpFreeCoins.qml:
import QtQuick 2.0
import QtQuick.Controls 2.1
Item {
property int t
property int c
ListModel{
id:ff
ListElement {
name: "ByFollow"
s: "Images/follow.png"
}
ListElement {
name: "ByLike"
s: "Images/care.png"
}
ListElement {
name: "ByComment"
s: "Images/chat.png"
}
}
ListView{
width:t-t/10
height: c/5
layoutDirection:Qt.LeftToRight
orientation: ListView.Horizontal
model: ff
spacing:50
delegate: Button{
contentItem: Image{
source: s
}}
}
}
property t is set equal to window width in main file and property c is set to window height. This is code of my Button.qml:
Button{//Below Right
width:profilePicture.width/2
height:profilePicture.width/2
x:profilePicture.x+profilePicture.width
y:profilePicture.y+profilePicture.height
contentItem: Image {
source: "Images/freecoins.png"
anchors.fill: parent
}
onClicked: PopUp{height:100;width:300;PopUpFreeCoins{t:a;c:b;}}
}
property a is window width and b is window height.
this line onClicked: PopUp{height:100;width:300;PopUpFreeCoins{t:a;c:b;}} has an error I don't know how to handle!
Here is the error:
Cannot assign object type PopUpFreeCoins_QMLTYPE_0 with no default
method
You need to create the Object somehow. You have multiple ways for dynamically create Objects. One way is to use Component.createObject(parent) which requires you to have a Component instantiated in your file.
Here you can also pass a Object ({property0 : value, property1:value ... }) as second argument, to set the properties of the Component to be instantiated. You should not set the parent to null as it might happen, that the JS-garbage collector is too aggressive once again.
Alternatively you can use the Loader to load it from either a source (QML-file) or sourceComponent. Here you won't have problems with the garbage collector.
import QtQuick 2.7
import QtQuick.Controls 2.0
ApplicationWindow {
width: 1024
height: 800
visible: true
Button {
text: 'create'
onClicked: test.createObject(this)
}
Button {
x: 200
text: 'load'
onClicked: loader.active = !loader.active
}
Loader {
id: loader
source: 'TestObj.qml'
active: false
}
Component {
id: test
TestObj {}
}
}
TestObj.qml includes the Window to be opened.
Alternatively you can have the Window created from the beginning, and just change the visible to true or false.

QML animation - moving the application window

I want to create an animation to move (or resize) my application Window built using QML.
I have the following code (most of it created by default when we create a QT quick Controls application:
main.cpp
#include <QApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
MainForm.ui.qml
import QtQuick 2.6
import QtQuick.Controls 1.5
import QtQuick.Layouts 1.3
Item {
width: 640
height: 480
property alias button1: button1
property alias button2: button2
RowLayout {
anchors.centerIn: parent
Button {
id: button1
text: qsTr("Press Me 1")
}
Button {
id: button2
text: qsTr("Press Me 2")
}
}
}
main.qml
import QtQuick 2.6
import QtQuick.Controls 1.5
import QtQuick.Dialogs 1.2
ApplicationWindow {
id: mainWindow
visible: true
width: 640
height: 480
title: qsTr("Hello World")
flags: Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint
menuBar: MenuBar {
Menu {
title: qsTr("File")
MenuItem {
text: qsTr("&Open")
onTriggered: console.log("Open action triggered");
}
MenuItem {
text: qsTr("Exit")
onTriggered: Qt.quit();
}
}
}
MainForm {
anchors.fill: parent
button1.onClicked: Qt.quit();
button2.onClicked: state = "other";
}
transitions: [
Transition {
from: "*"
to: "other"
NumberAnimation { properties: "x,y"; easing.type: Easing.InOutQuad; duration: 2000 }
}
]
states: [
State {
name: "other"
PropertyChanges {
target: mainWindow
x: x + 200
}
}
]
MessageDialog {
id: messageDialog
function show(caption) {
messageDialog.text = caption;
messageDialog.open();
}
}
}
With this code, I was simply trying to move my window 200 pixels to the right. When I try to run it, I get qrc:/main.qml:42 Cannot assign to non-existent property "states". I believe that is weird, because when I start typing "states" and choose to auto-complete, it builds to me the whole structure, so I thought it should exist...
I'm new to QML, and I'm not fully familiar with the several options of animations that exists. This one I've tried based on the example that comes with QT creator (animation.pro - code from transitions).
I believe it should be quite simple, right? Could you help me with this?
Qt Creator has a feature where you can insert code snippets using certain keywords. You can see which snippets are available by going to Tools > Options > Text Editor > Snippets.
Snippets will show up as red in the auto completion popup, and regular properties (or types, as is the case below) will show up as green:
So, ApplicationWindow doesn't have a states property. If you're ever in doubt, go to the documentation for the type you're interested in (e.g. http://doc.qt.io/qt-5/qml-qtquick-controls-applicationwindow.html) and click on the link that says "List of all members, including inherited members". This will show you all properties, functions, etc. belonging
to that type.
If you want to animate the window's position, you can use a NumberAnimation without using states:
import QtQuick 2.6
import QtQuick.Window 2.2
import QtQuick.Controls 1.5
ApplicationWindow {
id: window
width: 400
height: 400
visible: true
NumberAnimation {
id: xyAnimation
target: window
properties: "x,y"
easing.type: Easing.InOutQuad
duration: 2000
to: 500
}
Button {
text: "Start"
onClicked: xyAnimation.start()
}
}
state is a property in Item, however ApplicationWindow is not an Item. To add state/transition to an non-Item type, use StateGroup:
ApplicationWindow {
id: mainWindow
//your code...
MainForm {
button2.onClicked: { myWindowStates.state = "other";}
}
StateGroup {
id: myWindowStates
transitions: [
Transition {
from: "*"; to: "other"
NumberAnimation {
properties: "x,y"; easing.type: Easing.Linear;
duration: 2000
}
}
]
states: [
State {
name: "other"
PropertyChanges {
target: mainWindow
x: mainWindow.x + 200
explicit: true //Remember to set this
}
}
]
}
}
Remember to set PropertyChange.explict to true, otherwise the state behavior is wrong and your window will disappear after the transition finished.

QML zoom from a clicked rectangle to another UI element

I have 9:9 matrix of Rectangle elements on the main QML form with Repeater. What I want to implement is if user clicks on one of rectangles, it zooms to TextEdit widget which on Esc press zooms back.
Is it possible with QML?
If yes, how am I supposed to turn Rectangle to TextEdit and zoom this TextEdit to fill the parent?
Just starting to work with QML and can't quite get an answer from http://doc.qt.nokia.com/4.7-snapshot/qdeclarativeanimation.html yet.
Thank you.
1) Sure thing! This is more or less what QML is made for.
2) This is an example of how you can do what you want (not the only way to do it):
Rectangle {
id: parentRect
width: 500; height: 500
// Every item in the grid should look like this
Rectangle {
id: singleItem
color: "red"
state: "closed"
// Hidden text input, shown when user clicks
TextInput {
id: textInput
anchors.fill: parent
text: "Input here"
cursorVisible: true
}
// MouseArea that will catch the user click
MouseArea {
anchors.fill: parent
onClicked: singleItem.state = "open"
}
// Item states
states: [
State {
name: "closed"
PropertyChanges {target: singleItem; width: 25; height: 25}
PropertyChanges {target: textInput; opacity: 0}
},
State {
name: "open"
PropertyChanges {target: singleItem; width: parentRect.width; height: parentRect.height}
PropertyChanges {target: textInput; opacity: 1; focus: true}
}
]
// Transitions between states
transitions: Transition {
ParallelAnimation {
NumberAnimation {
target: singleItem
properties: "width,height"
duration: 1000
}
NumberAnimation {
target: textInput
property: "opacity"
duration: 1000
}
}
}
}
}
Even I'm new to qt-quick. I don't think it is possible to zoom unless we write our code to do such. I'm not sure though. :-)
This effect is good and it will b nice to see in coming versions. Try to give a feature request to the community <3

Resources