Qt QML for a digital dashboard - qt

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!

Related

Converting 2d coordinates to 3d coordinates in Qml qt3d

I have a window size width: 1500 height: 780, I would like to render the 3d object with 2d co-ordinates, giving z=1 as dummy value. Following is the qml code.(If i have to render at x=0,y=0 3d should object should render exactly the same place where the Rectangle in qml renders i.e window coordinates)
Entity {
id: root
property real x: 2.0
property real y: 0.0
property real z: 0.0
property real scale: 1
property var mainCam
property var forwardRenderer
property Material material
components: [ trefoilMeshTransform, mesh, root.material ]
Transform {
id: trefoilMeshTransform
property real userAngle: 900.0
translation:Qt.vector3d(0,1,1)
property real theta: 0.0
property real phi:0.0
property real roll: 0.0
rotation: fromEulerAngles(theta, phi, roll)
scale: root.scale
}
Mesh {
id: mesh
source: "assets/obj/cube.obj"
}
}
The code is exactly the same as wireframe example, including the camera settings. I tried to use the qt3d unproject api in qml but ended up unsuccessfully . Can you please help me with the clue?
Please read this document about How to convert world to screen coordinates and vice versa this is good for understanding some logics.
and also this.
In qt3d I get 3d coordinate by using RayCaster and ScreenRayCaster
it gives you the local position and world position and screen x , y
see this site from kdab and its example
RenderSettings{
//all components that you need like viewport , InputSettings ,...
ScreenRayCaster {
id: screenRayCaster
onHitsChanged: printHits("Screen hits", hits)
}
}
MouseHandler {
id: mouseHandler
sourceDevice: MouseDevice {}
onReleased: { screenRayCaster.trigger(Qt.point(mouse.x, mouse.y)) }
}
function printHits(desc, hits) {
console.log(desc, hits.length)
for (var i=0; i<hits.length; i++) {
console.log(" " + hits[i].entity.objectName, hits[i].distance,
hits[i].worldIntersection.x, hits[i].worldIntersection.y, hits[i].worldIntersection.z)
}
}

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

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

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.

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.

QML Animation with both "velocity" and infinite "loops"

I'm trying to put together an animation in which I get to specify the velocity (rather than the duration) and which loops forever. I came up with two non-working examples:
FirstTry.qml
import Qt 4.7
Rectangle {
width: 100; height: 100
Text {
text: "hello"
NumberAnimation on x {
to: 50;
loops: Animation.Infinite;
duration: 50 * Math.abs(to - from)
}
}
}
I get the following runtime warning while hello goes nuts on the screen (fair enough).
QDeclarativeExpression: Expression "(function() { return 50 * Math.abs(to - from) })" depends on non-NOTIFYable properties:
QDeclarativeNumberAnimation::to
QDeclarativeNumberAnimation::from
SecondTry.qml
import Qt 4.7
Rectangle {
width: 100; height: 100
Text {
text: "hello"
SmoothedAnimation on x {
to: 50;
loops: Animation.Infinite;
velocity: 50
}
}
}
This is more of a mistery -- SmoothedAnimation simply refuses to loop! The Animation runs once and then that's it.
So I have the following questions:
Is there a legal way to specify the velocity in the first example? I understand SmoothedAnimation is derived from NumberAnimation, so maybe it's possible in QML, not just in C++.
Is there a way to make SmoothedAnimation loop? Is the second example not working a bug or am I missing something?
Is there any other way to achieve these two behaviours at the same time?
just add "from" parameter explicitly:
import Qt 4.7
Rectangle {
width: 100; height: 100
Text {
text: "hello"
NumberAnimation on x {
from: 0;
to: 50;
loops: Animation.Infinite;
duration: 50 * Math.abs(to - from)
}
}
}
This is what I did as a temporary solution, I'm not sure if it's adequate, but it seem to be doing just what I needed.
SmoothedAnimation on x {
to: 50;
//loops: Animation.Infinite;
velocity: 50
onComplete: { restart (); }
}
I'm still interested in the answers to the questions, though.
Even if SmoothedAnimation doesn't accept loops parameter, you can place it inside SequentialAnimation and apply loops to this external cover. As an effect your smoothed animation will be played continuosly.

Resources