How to apply a smooth rotation animation on my needle rotation property? - qt

I have below QML. I need to apply a smooth animation on rotation. 'mycontroller' from c++ code will gives incremented gauge values in frequent intervals (say in 500 msecs). so I need a smooth transition on rotation.
Rectangle {
id : gauge
property real value : mycontroller.value
Image {
id : needle
x:50
y:190
z: -2
rotation: gauge.value
transformOrigin: Item.Right
source : "qrc:/images/needle.png";
}
}

You should use a behavior based approach:
Behavior on rotation { NumberAnimation { duration: 200 } }

Related

QML Animation: How to stop infinite animation in exact position?

I'm trying to stop infinite animation from function where position is known.
I need animation to animate until the x = pos and then to stop.
NumberAnimation on x {
id : animationObject
loops: Animation.Infinite
from: 0
to: 500
running: true
duration: 3000
}
I have tried to stop it in this way, but it doesn't help.
function stop(pos) {
animationObject.loops = 1;
animationObject.to = pos;
}
You can set an expression as value of the property running to be true if the position is not reached and false otherwise.
The x property is also associated to the signal onXChanged that will be triggered each time the item moved. You can also use it if you don't want/can't change the animation definition:
Rectangle {
anchors.fill: parent
Rectangle {
id: rect
width: 100
height: 100
color: "red"
property int bound: 50
NumberAnimation on x {
id : animationObject
loops: Animation.Infinite
from: 0
to: 100
running: Math.abs(rect.x - bound) > 1
duration: 3000
}
onXChanged: console.log(rect.x, Math.abs(rect.x - bound) > 1)
}
}
In the code above, the animation will be stopped when the rectangle reachs the X coordinate defined by the property bound.
As the value will be a floated number, we can't use the equality and have to use a margin error (1 in my code).

How do we translate a QML Rectangle on the Z axis, not just X and Y?

Is it possible to translate a QML Rectangle on the Z axis similar to how we can do in HTML with CSS transform:translateZ() and transform:translate3d()?
Applying transform: Translate {x: 0; y: 0; z: 100} on a Rectangle throws an error that the z property isn't defined.
I am able to apply transform: Rotation{} to a Rectangle with a z-axis rotation and it looks 3D. I was hoping I could translate things in 3D as well.
Is there a way to do it?
EDIT: I tried setting a Matrix4x4 like this:
transform: Matrix4x4 {
matrix: Qt.matrix4x4(
1,0,0,0,
0,1,0,0,
0,0,1,10,
0,0,0,1
)
}
I set the number 10 where I believe the Z translation is, but the Rectangle just disappears instead of getting a little closer to the camera.
Applying transform: Translate {x: 0; y: 0; z: 100} on a Rectangle throws an error as expected as Translate only has only x and y properties (See http://doc.qt.io/qt-5/qml-qtquick-translate.html).
The Transform does not correspond with how you are trying to use it as z is not the position along the z-axis. z is the "stacking order" which is used to control which items are drawn on top or below other items (http://doc.qt.io/qt-5/qml-qtquick-item.html#z-prop).
If you wanted to let your Rectangle appear "a little closer to the camera", Scale seems like a possible Transform to use (http://doc.qt.io/qt-5/qml-qtquick-scale.html) or just use the item's scale property (http://doc.qt.io/qt-5/qml-qtquick-item.html#scale-prop).
This answer might also be helpful to you as someone else had a similar question. It illustrates how you can rotate along different axis. For example, You could do something like: transform: Rotation { origin.x: 50; origin.y: 55; axis { x: 0; y: 1; z: 0 } angle: 60}.
Note though that it is not possible to actually translate a QML Rectangle along the "z-axis". So if your goal is to create a 3D scene in QML, two possible options are Qt Canvas3D or the Qt3D module. If you want to use three.js check out this post

ListView scrolling animation

I want to implement a scrolling animation for QML ListView. Here is a sample image:
Can anybody advise me for implementing this?
Thank you.
The ViewTransition provides a lot of interesting examples on how to animate a ListView for operations like populate (the transition for the initial items at component creation), add, remove (self-explanatory) as well as other operations.
Given a ListView you define an element Transition for each operation you want to animate. The animation framework can be exploited to create compound animations, by simply combining the basic animations to create the (more or less) complex behaviour you are interested in (see also here for an actual example).
Here a definition for a ListView (the first linked document provides some nice images):
ListView {
// data model, delegate, other usual stuff here...
// transitions for insertion/deletation of elements
add: Transition {
NumberAnimation { property: "opacity"; from: 0; to: 1.0; duration: 500 }
NumberAnimation { property: "scale"; easing.type: Easing.OutBounce; from: 0; to: 1.0; duration: 750 }
}
addDisplaced: Transition {
NumberAnimation { properties: "y"; duration: 600; easing.type: Easing.InBack }
}
remove: Transition {
NumberAnimation { property: "scale"; from: 1.0; to: 0; duration: 200 }
NumberAnimation { property: "opacity"; from: 1.0; to: 0; duration: 200 }
}
removeDisplaced: Transition {
NumberAnimation { properties: "x,y"; duration: 500; easing.type: Easing.OutBack }
}
}
Finally, note that some behaviours can be obtained by using Shaders and combining animation on the elements and transitions on the delegate/elements of the delegate. A nice example is Tweet Search, in which a shading effect (see [ShaderEffect][5]) on the bar item is combined with a simple Transition on ListView add.
EDIT
Provide a customized scrolling like in the examples requires to take in account the position of the Items inside the ListView. A key to a working solution is to find a way to calculate the current position of the Item inside the visible part of the view and use that value to calculate the appropriate transformation. ListView derives from Flickable which has several useful properties for this purpose.
However, the y property of the Item is referred to the overall height of the content inside the ListView. To have its position w.r.t. the beginning of the visible area we can use the contentY property. A picture is worth a thousand words in this case:
The difference between y and contentY provides a value which can be used to calculate the required transformation factor (maybe in relation to the height of the ListView). Indeed, as the ListView is flicked, the two values and their difference change and so changes the transformation factor for a specific Item.
Such transformation covers only part of the problem. Once the flicking/movement ends the Items animation must be "finished" to make all the visible items usable. For this purpose we can exploit Binding and its when property to activate the finishing animation only when required, i.e. when flicking or dragging ends.
Given all this (boring) introduction, let's take in account the second animation (the simpler one). Here we can use scale to obtain the desired effect. The delegate code inside the ListView looks like the following:
ListView {
id: list
model: 100
spacing: 10
delegate: Rectangle {
id: itemDelegate
property int listY: y - list.contentY // stores the difference between the two values
width: parent.width
height: 50
border.color: "lightgray"
color: "red"
Binding {
target: itemDelegate
property: "scale"
value: 1 - listY / list.height / 2 // the "scale" property accepts values in the range [0, 1]
when: list.moving || list.flicking || list.dragging // ...when moved around
}
Binding {
target: itemDelegate
property: "scale"
value: 1 // flick finished --> scale to full size!
when: !(list.moving || list.dragging) // not moving or dragging any more
}
Behavior on scale {
NumberAnimation { duration: 100; to: 1}
enabled: !(list.flicking || list.dragging) // active only when flick or dragging ends!
}
}
}
The first Binding define the scaling factor on the basis of listY whereas the second one set the scaling to 1 but only when the ListView is not moving. The final Behavior is necessary to smooth the transition to the fully scaled Item.
The third effect can be obtained in a similar fashion with a Rotation:
ListView {
anchors.fill: parent
id: list
spacing: 10
model: 100
delegate: Rectangle {
id: itemDelegate
property int listY: y - list.contentY
property real angleZ: (90 * listY) / list.height // 0 - 90 degrees
transform: Rotation { origin.x: width / 2; origin.y: 30; axis { x: 1; y: 0; z: 0 } angle: angleZ}
//transform: Rotation { origin.x: 0; origin.y: 30; axis { x: 1; y: 1; z: 0 } angle: angleZ} <--- I like this one more!
width: parent.width
height: 50
border.color: "lightgray"
color: "red"
Binding {
target: itemDelegate
property: "angleZ"
value: 0
when: !(list.moving || list.dragging)
}
Behavior on angleZ {
NumberAnimation {duration: 200; to: 0}
enabled: !(list.flicking || list.dragging)
}
}
}
This time I've choosen to (arbitrarily) use only one Binding. The same could have been made for the first example, i.e. we could have written in the first delegate scale: 1 - listY / list.height / 2.
Following a similar approach you can also create the first animation and others. For the first animation I think that combining a Rotation with a Translate should suffice.
After many hours of work, research and #BaCaRoZzo's great help (Thanks #BaCaRoZzo), I finally found the right solution. Just use Component.onCompleted() event handler to run the animation associated with each delegate.
Here is an example, enjoy!
import QtQuick 2.3
ListView {
anchors.fill: parent
id: list
model: 100
cacheBuffer: 50
delegate: Rectangle {
id: itemDelegate
Component.onCompleted: showAnim.start();
transform: Rotation { id:rt; origin.x: width; origin.y: height; axis { x: 0.3; y: 1; z: 0 } angle: 0}// <--- I like this one more!
width: parent.width
height: 50
color: index % 2 === 0 ? "#EEE" : "#DDD"
SequentialAnimation {
id: showAnim
running: false
RotationAnimation { target: rt; from: 180; to: 0; duration: 800; easing.type: Easing.OutBack; property: "angle" }
}
}
}
A PathView displays data from models created from built-in QML types like ListModel and XmlListModel, or custom model classes defined in C++ that inherit from QAbstractListModel.
The view has a model, which defines the data to be displayed, and a delegate, which defines how the data should be displayed. The delegate is instantiated for each item on the path. The items may be flicked to move them along the path.

Qt QML for a digital dashboard

I am trying to develop in Qt QML a digital dashboard composed by a
speedometer and a tachometer with a needle each.
The problem of this design arises when i am involved in a rotation
of the needle: in this case, it has a jerky movement and it is not as
fluent as a real needle.
For instance, let us suppose to have 0 km/h i.e. the needle situated at
0 degrees and then I want to show 100 km/h situated at 90 degrees, the
needle reaches this angle with a sequence of fast jerks and not as a
unique fluent movement.
Does anyone have an idea to solve the inconvenient? Should I have to
use openGL?
I report the code below (I have used the QML Rotation function but it
is not enough)
Image {
id: needle
source: "../../images/needle.png"
antialiasing: true
transform: Rotation {
id: needleRotation
origin.x: 80;
origin.y: 80;
angle: 0
Behavior on angle {
RotationAnimation {
id: needleRotationAnimation
direction: RotationAnimation.Shortest;
easing.type: Easing.InOutCubic;
duration: 20;
}
}
}
}
I learn this today.
Try with the SmoothedAnimation instead, will achieve the objective you want, since SmoothedAnimation is calculating for the next paint() the current position, and not the initial position.
Image {
id: needle
source: "../../images/needle.png"
antialiasing: true
transform: Rotation {
id: needleRotation
origin.x: 80;
origin.y: 80;
angle: 0
Behavior on angle {
SmoothedAnimation {
id: needleRotationAnimation
easing.type: Easing.InOutCubic;
duration: 20;
}
}
}
I will like to know a little bit more about your app since maybe its really necessary for you the
direction: RotationAnimation.Shortest;
If its necessary just tell me and I'll try to have a further look!

QML NumberAnimation.duration behaviour

I'm trying to make a player move smoothly towards a destination in QML. I'm using a NumberAnimation to animate the x,y position changes. The NumberAnimation's duration should be proportional to the distance the player has to travel, so that the player moves at the same speed regardless of how far away they are from their destination.
import QtQuick 1.1
Item {
width: 720
height: 720
MouseArea {
anchors.fill: parent
onClicked: {
var newXDest = mouse.x - player.width / 2;
var newYDest = mouse.y - player.height / 2;
var dist = player.distanceFrom(newXDest, newYDest);
// Make duration proportional to distance.
player.xMovementDuration = dist; // 1 msec per pixel
player.yMovementDuration = dist; // 1 msec per pixel
console.log("dist = " + dist);
player.xDest = newXDest;
player.yDest = newYDest;
}
}
Rectangle {
id: player
x: xDest
y: yDest
width: 32
height: 32
color: "blue"
property int xDest: 0
property int yDest: 0
property int xMovementDuration: 0
property int yMovementDuration: 0
function distanceFrom(x, y) {
var xDist = x - player.x;
var yDist = y - player.y;
return Math.sqrt(xDist * xDist + yDist * yDist);
}
Behavior on x {
NumberAnimation {
duration: player.xMovementDuration
// duration: 1000
}
}
Behavior on y {
NumberAnimation {
duration: player.yMovementDuration
// duration: 1000
}
}
}
Rectangle {
x: player.xDest
y: player.yDest
width: player.width
height: player.height
color: "transparent"
border.color: "red"
}
}
My problem can be demonstrated by running the application above and following these steps:
Click on the bottom right hand corner of the screen.
Immediately click in the centre (or closer towards the top left) of the screen.
On the second click (while the rectangle is still moving), it seems that the rectangle's number animation is stopped (which is what I want) but it assumes the position of the destination (not what I want). Instead, I want the animation to stop and the rectangle to assume the position at which it was stopped, then to continue on to the new destination.
The correct behaviour - ignoring that the movement speed becomes disproportional - can be seen by setting both of the NumberAnimation.durations to 1000.
I think that you are looking for SmoothedAnimation. There are only two types of animation that deal nicely with the destination changing before the animation is completed. That is SmoothedAnimation and SpringAnimation. Both of these use the current position and velocity to determine the position in the next frame. Other animation types move the position along a predetermined curve.
Simply changing NumberAnimation to SmoothedAnimation makes your example look correct to me.

Resources