I tried to get the mouse click position in qml Image component, but what I got is not the real pixel-based image position, how can I get the pixel-based position of the image?
this is my qml code
Image {
id: sourceImage
width: parent.width
height: parent.height
fillMode: Image.PreserveAspectFit
source: "D://test.png"
mipmap: true
smooth: true
antialiasing: true
MouseArea {
width: parent.width
height: parent.height
focus: true
anchors.fill: parent
onClicked: {
print("clicked:", mouse.x,mouse.y)
}
}
}
the real image size is 3840*1260, but when I click the bottom-right position with the mouse, it prints clicked: 683 547
A lot of the code is boilerplate for debugging. The important part is the three functions mapToImage() and getXPosition()/getYPosition(). The latter is for getting the offset at which the image is drawn, when Image.PreservedAspectFit can't fill the Image and horizontalAlginment/verticalAlignment are used.
The map function uses sourceSize and paintedWidth/paintedHeight to get the scaling between the original size of the image and the actual drawn image. Keep in mind that when changing sourceSize and not letting the image set it, this method of getting the scaling might not work.
Just a note from the documentation:
sourceSize can be cleared to the natural size of the image by setting
sourceSize to undefined.
import QtQuick
import QtQuick.Controls
Window {
id: root
visible: true
width: 800
height: 600
title: qsTr("Image Picking")
function getXPosition(image : Image) : real {
switch (image.horizontalAlignment) {
case Image.AlignLeft:
return 0
case Image.AlignRight:
return image.width - image.paintedWidth
case Image.AlignHCenter:
default:
return (image.width - image.paintedWidth) * 0.5
}
}
function getYPosition(image : Image) : real {
switch (image.verticalAlignment) {
case Image.AlignTop:
return 0
case Image.AlignBottom:
return image.height - image.paintedHeight
case Image.AlignVCenter:
default:
return (image.height - image.paintedHeight) * 0.5
}
}
function mapToImage(mouse : MouseEvent, image : Image) {
root.xScale = image.paintedWidth / image.sourceSize.width
root.yScale = image.paintedHeight / image.sourceSize.height
root.xImgPosition = Math.floor((mouse.x - root.getXPosition(image)) / root.xScale)
root.yImgPosition = Math.floor((mouse.y - root.getYPosition(image)) / root.yScale)
}
property real xScale: 0
property real yScale: 0
property real xImgPosition: 0
property real yImgPosition: 0
Image {
id: image
anchors.centerIn: parent
width: 320
height: 240
fillMode: Image.PreserveAspectFit
//horizontalAlignment: Image.AlignLeft
source: "https://picsum.photos/id/17/200/300"
mipmap: true
smooth: true
antialiasing: true
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onPositionChanged: function(mouse) { root.mapToImage(mouse, image) }
}
Rectangle {
anchors.fill: parent
color: "transparent"
border {
width: 1
color: "gray"
}
}
// Debug rectangle showing the real dimension of the image before clipping by the fillMode
Rectangle {
x: root.getXPosition(image)
y: root.getYPosition(image)
width: image.paintedWidth
height: image.paintedHeight
color: "transparent"
border {
width: 1
color: "red"
}
}
}
Rectangle {
width: column.width + 40
height: column.height + 40
color: Qt.rgba(0.3, 0.3, 0.3, 0.4)
Column {
id: column
x: 20
y: 20
spacing: 4
ComboBox {
width: 180
textRole: "text"
valueRole: "value"
onActivated: image.fillMode = currentValue
Component.onCompleted: currentIndex = indexOfValue(image.fillMode)
model: [
{ value: Image.Stretch, text: qsTr("Stretch") },
{ value: Image.PreserveAspectFit, text: qsTr("Preserve Aspect Fit") },
{ value: Image.PreserveAspectCrop, text: qsTr("Preserve Aspect Crop") }
]
}
Text { text: "Mouse: " + mouseArea.mouseX + ", " + mouseArea.mouseY }
Text { text: "Image: " + image.width + ", " + image.height }
Text { text: "Painted: " + image.paintedWidth + ", " + image.paintedHeight }
Text { text: "Source: " + image.sourceSize.width + ", " + image.sourceSize.height }
Text { text: "Scaling: " + root.xScale + ", " + root.yScale }
Text { text: "Position: " + root.xImgPosition + ", " + root.yImgPosition }
}
}
}
Related
I need to move the cube according to the coordinates that I enter in ScrollView.
import QtQuick 2.15
import QtQuick.Window 2.14
import QtQuick3D 1.15
import QtQuick.Controls 2.14
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
visibility: "Maximized"
property int move_x: 5
property int move_y: 5
property int move_z: 5
Node{
id: standAloneScene
DirectionalLight {
ambientColor: Qt.rgba(1.0, 1.0, 1.0, 1.0)
}
Node{
Model {
id: model
source: "#Cube"
x: 0
y: 0
z: 0
materials: [
DefaultMaterial {
diffuseColor: Qt.rgba(0.053, 0.130, 0.219, 0.75)
}
]
}
}
ParallelAnimation{
id: moving
NumberAnimation {
target: model
property: "x"
from: 0
to: move_x
duration: 2000
easing.type: Easing.InOutQuad
}
NumberAnimation {
target: model
property: "y"
from: 0
to: move_y
duration: 2000
easing.type: Easing.InOutQuad
}
NumberAnimation {
target: model
property: "z"
from: 0
to: move_z
duration: 2000
easing.type: Easing.InOutQuad
}
}
OrthographicCamera {
id: cameraOrthographicFront
eulerRotation.y: 45
eulerRotation.x: -45
x: 600
y: 800
z: 600
}
}
Rectangle {
id: view
anchors.top: parent.top
anchors.left: parent.left
width: parent.width
height: parent.height
color: "#848895"
View3D {
id: isometria
anchors.fill: parent
importScene: standAloneScene
camera: cameraOrthographicFront
}
Rectangle{
id: control
color: "grey"
width: 400
anchors.top: view.top
anchors.bottom: view.bottom
anchors.right: view.right
Button {
id: start
height: control.width/4
anchors.top: control.top
anchors.left: control.left
anchors.right: control.right
text: "start"
font.pixelSize: height
onClicked: {
move.getListCoordinates(hellotext.text)
for(var i=0; i<move.get_number_crds(); i++){
move.next(i);
move_x = move.get_x()
move_y = move.get_y()
move_z = move.get_z()
moving.restart();
}
}
}
ScrollView{
id: textarea
anchors.top: start.bottom
anchors.right: control.right
anchors.left: control.left
anchors.bottom: control.bottom
TextArea{
id: hellotext
font.pixelSize: 40
}
}
}
}
}
When the button is clicked, coordinates are read from ScrollView and written to a vector using the move class function. Then the cycle starts from 0 to the number of elements in the vector. Coordinates are passed in turn to move_x, move_y and move_z, then the animation is restarted.
The implementation of the move class is shown below
move.h
#ifndef MOVE_H
#define MOVE_H
#include <QObject>
#include <QDebug>
#include <QVector>
struct Position
{
int x;
int y;
int z;
};
class Move: public QObject
{
Q_OBJECT
public:
Move(QObject *parent = nullptr);
private:
QVector<Position> coordinates;
Position current_position;
signals:
private:
Position StringParsing(QString st);
public slots:
void getListCoordinates(QString list_crd);
int get_number_crds();
void next(int i);
int get_x();
int get_y();
int get_z();
};
#endif // MOVE_H
move.cpp
#include "move.h"
#include <QString>
Move::Move(QObject *parent): QObject(parent) {}
Position Move::StringParsing(QString crd_st){
Position crd;
crd.x = (crd_st.mid(1, crd_st.indexOf('Y') - 1)).toInt();
crd.y = crd_st.mid(crd_st.indexOf('Y') + 1, crd_st.indexOf('Z') - crd_st.indexOf('Y') - 1).toInt();
crd.z = crd_st.mid(crd_st.indexOf('Z') + 1, crd_st.length() - crd_st.indexOf('Z') - 1).toInt();
return crd;
}
void Move::getListCoordinates(QString list_crd){
list_crd += "\n";
while(list_crd.length() != 0){
QString crd = list_crd.mid(0, list_crd.indexOf('\n')+1);
list_crd.remove(0, list_crd.indexOf('\n')+1);
coordinates.push_back(StringParsing(crd));
qDebug() << crd << Qt::endl;
}
}
int Move::get_number_crds(){
return coordinates.size();
}
void Move::next(int i){
current_position = coordinates[i];
}
int Move::get_x(){
qDebug() << current_position.x << Qt::endl;
return current_position.x;
}
int Move::get_y(){
qDebug() << current_position.y << Qt::endl;
return current_position.y;
}
int Move::get_z(){
qDebug() << current_position.z << Qt::endl;
return current_position.z;
}
But the object is moved only to the last coordinates I recorded. Can you tell me how I can implement this? Thanks
А solution to this problem.
import QtQuick 2.15
import QtQuick.Window 2.14
import QtQuick3D 1.15
import QtQuick.Controls 2.14
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
visibility: "Maximized"
property int i: 0
property int move_x: 0
property int move_y: 0
property int move_z: 0
Node{
id: standAloneScene
DirectionalLight {
ambientColor: Qt.rgba(1.0, 1.0, 1.0, 1.0)
}
Node{
Model {
id: model
source: "#Cube"
x: 0
y: 0
z: 0
materials: [
DefaultMaterial {
diffuseColor: Qt.rgba(0.053, 0.130, 0.219, 0.75)
}
]
}
}
// SequenceAnimation {}
SequentialAnimation{
id: myAnimation
ScriptAction{
script: {
if(i < move.get_number_crds()){
move.next(i);
move_x = move.get_x();
move_y = move.get_y();
move_z = move.get_z();
}
if(i > move.get_number_crds()){
i = 0;
myAnimation.stop();
}
}
}
ParallelAnimation{
id: moving
NumberAnimation {
target: model
property: "x"
to: move_x
duration: 2000
easing.type: Easing.InOutQuad
}
NumberAnimation {
target: model
property: "y"
to: move_y
duration: 2000
easing.type: Easing.InOutQuad
}
NumberAnimation {
target: model
property: "z"
to: move_z
duration: 2000
easing.type: Easing.InOutQuad
}
}
ScriptAction{
script: {
i++;
myAnimation.restart();
}
}
}
OrthographicCamera {
id: cameraOrthographicFront
eulerRotation.y: 45
eulerRotation.x: -45
x: 600
y: 800
z: 600
}
}
Rectangle {
id: view
anchors.top: parent.top
anchors.left: parent.left
width: parent.width
height: parent.height
color: "#848895"
View3D {
id: isometria
anchors.fill: parent
importScene: standAloneScene
camera: cameraOrthographicFront
}
Rectangle{
id: control
color: "grey"
width: 400
anchors.top: view.top
anchors.bottom: view.bottom
anchors.right: view.right
Button {
id: start
height: control.width/4
anchors.top: control.top
anchors.left: control.left
anchors.right: control.right
text: "start"
font.pixelSize: height
onClicked: {
move.getListCoordinates(hellotext.text)
myAnimation.start();
}
}
ScrollView{
id: textarea
anchors.top: start.bottom
anchors.right: control.right
anchors.left: control.left
anchors.bottom: control.bottom
TextArea{
id: hellotext
font.pixelSize: 40
}
}
}
}
}
I'm trying to change focus of an image while pressing keys (left, right, up and down) in GridView. When I press left, right, up or down key, I should change image focus and change the image when focus on that image is true. Otherwise, if focus is not on the image, old image should be seen.
Here is what I have by now:
And here is my code:
import QtQuick 2.15
import QtQuick.Window 2.15
Window {
width: 1920
height: 1080
visible: true
title: qsTr("Hello World")
Component.onCompleted: {
mojgrid.focus = true
}
function dobioResponseNapraviModel(response) {
console.log("dobioResponseNapraviModel", typeof response)
mojgrid.model=response
}
function request(){
console.log("BOK")
const xhr=new XMLHttpRequest()
const method="GET";
const url="http://api.themoviedb.org/4/list/1";
xhr.open(method, url, true);
xhr.setRequestHeader( "Authorization", 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI5YjBkOGVlMGQzODdiNjdhYTY0ZjAzZDllODM5MmViMyIsInN1YiI6IjU2MjlmNDBlYzNhMzY4MWI1ZTAwMTkxMyIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.UxgW0dUhS62m41KjqEf35RWfpw4ghCbnSmSq4bsB32o');
xhr.onreadystatechange=function(){
if(xhr.readyState===XMLHttpRequest.DONE){
var status=xhr.status;
if(status===0 || (status>=200 && status<400)){
//the request has been completed successfully
// console.log(xhr.responseText.results)
dobioResponseNapraviModel(JSON.parse(xhr.responseText).results)
}else{
console.log("There has been an error with the request", status, JSON.stringify(xhr.responseText))
}
}
}
xhr.send();
}
/* function request(url, callback) {
var xhr=new XMLHttpRequest();
xhr.open("GET", url, true)
xhr.onreadystatechange = function() {
if(xhr.readyState===4) {
callback(xhr.responseText)
}
}
xhr.open("GET", url)
xhr.setRequestHeader( "Authorization", 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI5YjBkOGVlMGQzODdiNjdhYTY0ZjAzZDllODM5MmViMyIsInN1YiI6IjU2MjlmNDBlYzNhMzY4MWI1ZTAwMTkxMyIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.UxgW0dUhS62m41KjqEf35RWfpw4ghCbnSmSq4bsB32o');
xhr.send()
}*/
GridView {
id:mojgrid
anchors.fill: parent
cellWidth: 250
cellHeight: 250
model:request()
currentIndex: modelData.id
keyNavigationEnabled: true
focus:true
Keys.onPressed:{
if((event.key === Qt.Key_Left) || (event.key===Qt.Key_Right) || (event.key===Qt.Key_Up) || (event.key===Qt.Key_Down)){
image.source="http://image.tmdb.org/t/p/w400"+modelData.poster_path
}
}
/* Keys.onUpPressed: {
request()
}*/
delegate: Rectangle{ id: rect; width: 350; height: 400; color:'gray';
Image{id:img; width:parent.width; height:parent.height-200
//fillMode: Image.PreserveAspectFit
//source:"http://image.tmdb.org/t/p/w400" + modelData.backdrop_path
source:focus?"http://image.tmdb.org/t/p/w400"+modelData.poster_path : "http://image.tmdb.org/t/p/w400" + modelData.backdrop_path
Rectangle{
id:rect2
width:parent.width
height:text.height
anchors.top:img.bottom
color:'black'
Text{
id:text
text:modelData.title
font.pointSize: 11
//anchors.top:image.bottom
elide:Text.ElideNone
color:'white'
}
}
MouseArea{
id:mouse
anchors.fill:parent
onClicked: {
parent.focus=true
}
}
}
Rectangle{
id:rect3
width:parent.width
height:200
anchors.top:rect.bottom
color:'red'
z:10
Text{
text:modelData.release_date
anchors.left:rect.left
anchors.top:rect.bottom
color: 'white'
}
}
}
}
}
I have Keys.onPressed here with an if condition, but it doesn't work. Can someone help me?
I simplified and reformat your code little bit but this code snippet is doing what do you want to do. When key navigation is enabled GridView is handling index update by itself. Actually key navigation is working and when you press keys current index is updated. GridView also handles limits on navigation, when you press down in the last row nothing happens as same as when you press left on the first column. The trick is using currentindex to update image.
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
width: 1920
height: 1080
visible: true
title: qsTr("Hello World")
function dobioResponseNapraviModel(response) {
console.log("dobioResponseNapraviModel", typeof response)
mojgrid.model = response
}
GridView {
id: mojgrid
anchors.fill: parent
cellWidth: 250
cellHeight: 250
model: request()
keyNavigationEnabled: true
focus: true
delegate: Rectangle {
id: rect
width: 350
height: 400
color: 'gray'
property bool isCurrent: mojgrid.currentIndex === index
Image {
id: img
width: parent.width
height: parent.height - 200
source: isCurrent ? "http://image.tmdb.org/t/p/w400"
+ modelData.poster_path : "http://image.tmdb.org/t/p/w400"
+ modelData.backdrop_path
Rectangle {
id: rect2
width: parent.width
height: text.height
anchors.top: img.bottom
color: 'black'
Text {
id: text
text: modelData.title
font.pointSize: 11
//anchors.top:image.bottom
elide: Text.ElideNone
color: 'white'
}
}
MouseArea {
id: mouse
anchors.fill: parent
onClicked: {
mojgrid.currentIndex = index
}
}
}
}
}
function request() {
console.log("BOK")
const xhr = new XMLHttpRequest()
const method = "GET"
const url = "http://api.themoviedb.org/4/list/1"
xhr.open(method, url, true)
xhr.setRequestHeader(
"Authorization",
'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI5YjBkOGVlMGQzODdiNjdhYTY0ZjAzZDllODM5MmViMyIsInN1YiI6IjU2MjlmNDBlYzNhMzY4MWI1ZTAwMTkxMyIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.UxgW0dUhS62m41KjqEf35RWfpw4ghCbnSmSq4bsB32o')
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.DONE) {
var status = xhr.status
if (status === 0 || (status >= 200 && status < 400)) {
dobioResponseNapraviModel(JSON.parse(
xhr.responseText).results)
} else {
console.log("There has been an error with the request",
status, JSON.stringify(xhr.responseText))
}
}
}
xhr.send()
}
}
I have following QML GridView:
GridView
{
id: ueProductGridView
antialiasing: true
clip: true
Layout.fillWidth: true
Layout.fillHeight: true
cellWidth: 200
cellHeight: 200
delegate: Rectangle
{
id: test
width: 192
height: 192
color: "red"
Text
{
anchors.fill: parent
text: index
}
transform:
[
Rotation
{
id: plateRotation
angle: -90
axis { x: 0; y: 1; z: 0 }
origin.x: -200
origin.y: 0
}
] // transform
SequentialAnimation
{
id: addAnimation
PauseAnimation
{
duration: Math.random()*2000
}
NumberAnimation
{
target: plateRotation
property: "angle"
to: 0
duration: 1000
}
}
SequentialAnimation
{
id: removeAnimation
PropertyAction
{
target: test
property: "GridView.delayRemove"
value: true
}
NumberAnimation
{
target: test
property: "scale"
to: 0
duration: 1000
}
PropertyAction
{
target: test
property: "GridView.delayRemove"
value: false
}
}
GridView.onAdd:
{
addAnimation.start();
} // onAdd
GridView.onRemove:
{
removeAnimation.start();
} // onRemove
} // delegate
Component.onCompleted:
{
model=10;
} // onCompleted:
} // GridView
Now, why delegate animations do not work, i.e., why GridView is empty? The code regarding animations was taken from tutorial and in there it works. However, if I comment/remove all code regarding animations, delegates are visible in GridView and it is all ok:
GridView
{
id: ueProductGridView
antialiasing: true
clip: true
Layout.fillWidth: true
Layout.fillHeight: true
cellWidth: 200
cellHeight: 200
delegate: Rectangle
{
id: test
width: 192
height: 192
color: "red"
Text
{
anchors.fill: parent
text: index
}
} // delegate
Component.onCompleted:
{
model=10;
} // onCompleted:
} // GridView
The animations associated to insertion/removal of elements from the views are Transitions (e.g. see add), between different States and are indeed called ViewTransitions. You should really take a deep look at the documentation page of this type: it is full of nice examples and describes in great details how addition/removal animations should be implemented.
When you define a ViewTransition, any property referenced inside it, if not differently targeted, refer a delegate property. Hence, if you write inside your GridView:
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 }
}
you are saying that each time a new delegate is added to the grid, its opacity as well as scale properties should be animated. Top level animations, like in this case, run in parallel so the delegate is scaled and made visible at the same time.
Now, if you want to animate nested properties, like in the case of the Rotation angle, the easiest way is to alias it inside the delegate. That way it can be handled exactly the same way as any other delegate property, resulting in a clearer and simpler code.
It should be noted that the animations in your example does not work also because they are associated to add Transition. Such Transition is not used during model initialisation when instead the populate Transition is used. From the documentation:
This property holds the transition to apply to the items that are initially created for a view.
It is applied to all items that are created when:
The view is first created
The view's model changes
The view's model is reset, if the model is a QAbstractItemModel subclass
Finally, an advice. If you animate addition and removal of elements, especially if the animation is slow, it is also important to animation the adjustment made by the view to the other elements. Animating them in a graceful way can improve visual feeling A LOT. Hence, when you provide a add and a remove transition, take in account also the addition of a addDisplaced and a removeDisplaced Transition.
Here follows a modified version of your code that shows all the points discussed above:
import QtQuick 2.5
import QtQuick.Window 2.2
Window {
id: window
width: 600
height: 400
visible: true
ListModel {
id: model
ListElement { code: "0" }
ListElement { code: "1" }
ListElement { code: "2" }
ListElement { code: "3" }
ListElement { code: "4" }
ListElement { code: "5" }
}
GridView {
id: ueProductGridView
anchors.fill: parent
antialiasing: true
clip: true
cellWidth: 200
cellHeight: 200
delegate: Rectangle {
width: 192
height: 192
color: "red"
property alias angle: rot.angle // alias!
Text {
anchors.centerIn: parent
text: code
font.pixelSize: 30
}
transform: Rotation {
id: rot
angle: -90
axis { x: 0; y: 1; z: 0 }
origin.x: -200
origin.y: 0
}
MouseArea {
anchors.fill: parent
onClicked: ueProductGridView.model.remove(index)
}
} // delegate
add: Transition {
NumberAnimation { property: "opacity"; from: 0; to: 1.0; duration: 500 } //since is already at 1.0 we should enforce the start from 0
NumberAnimation { property: "scale"; easing.type: Easing.OutBounce; from: 0; to: 1.0; duration: 750 }
}
addDisplaced: Transition {
NumberAnimation { properties: "x,y"; duration: 200; easing.type: Easing.InBack }
}
remove: Transition {
NumberAnimation { property: "scale"; from: 1.0; to: 0; duration: 200 }
}
removeDisplaced: Transition {
NumberAnimation { properties: "x,y"; duration: 200; easing.type: Easing.OutBack }
}
populate: Transition {
NumberAnimation { properties: "angle"; to: 0; duration: 500 }
}
}
Component.onCompleted:{ ueProductGridView.model= model }
}
I'm developing a progress bar in QML.
But the working is not working for all parameter values.
Its more bit of logical issue in UI
Requesting everyone to review it.
below is the code snippet
Rectangle
{
width: 500; height: 480
.....
color: "lightyellow"
Rectangle {
id: container
....
Row {
id:repeaterid
Repeater {
id: repeater
model: 100
Item { id: smallrect2; opacity:0.5; width:_width; height:_height
Rectangle { id: smallrect; color: _newColor }
......
}
}
}
Timer {
id: progressTimer
interval: 100
onTriggered: {
if ((slider.x + slider.width) < repeaterid.width)
{
slider.x += _width
var item = repeater.itemAt(indexCurrent)
item._newColor = "red"
indexCurrent++
}
else
{
progressTimer.repeat = false
}
}
}
Rectangle {
id: slider
// Adjust the dimensions of slider
x: repeaterid.x
y: repeaterid.y
width: _width
height: _height
}
}
}
The desired behaviour is achieved when value of _width is 30 and the model value in the repeater is 18, but as the value is decreased the slider in progress bar doesn't complete its path ( width = 5, model =100 ) or if increased it moves out of the path.
Solved : Adjusted model value according to container size & rectangle size
Is it possible to have a fade in/out animation when the source of an Image element is being changed ?
Do I need two Image elements ? Changing the opacity of one of the from 0 to 1 and another from 1 to 0 ?
To do this without much hassle. Run animations in this way:
Image {
id: toBeCreated
NumberAnimation on opacity {
id: createAnimation
from: 0
to: 1
duration: 2000
}
Component.onCompleted: createAnimation.start()
}
Image {
id: toBeDeleted
NumberAnimation on opacity {
id: destroyAnimation // start this animation from the function where you want to create new Images
to: 0
duration: 2000
onRunningChanged: {
if (!running) {
console.log("Destroying...")
toBeDeleted.destroy();
}
}
}
}
I Know its a little late but felt like sharing
Inspired by RajaRaviVarma ans i tried something like
A Qml for FadeInOut ImageView
import QtQuick 2.0
Item {
property string imageSource : ""
property string imageSourceTemp : ""
property real parentWidth: 0
property real parentHeight: 0
onImageSourceChanged:
{
destroyAnimation.start()
createAnimation.start()
}
Image {
id: toBeDeleted
source: imageSourceTemp
width: parentWidth
height: parentHeight
NumberAnimation on opacity {
id: destroyAnimation
to: 0.5
duration: 400
onRunningChanged: {
if (!running) {
}
}
}
}
Image {
id: toBeCreated
source: imageSource
width: parentWidth
height: parentHeight
NumberAnimation on opacity {
id: createAnimation
from: 0
to: 1
duration: 800
onRunningChanged: {
if (!running) {
imageSourceTemp = imageSource
}
}
}
}
}
And to use it Like
FadeinFadeOutImage {
id: song_image
imageSource: songImage
parentWidth: width
parentHeight: height
width: 406*scaleFactor
height: 406*scaleFactor
}