PDA

View Full Version : Crossfade two images in QML



sysv
8th September 2016, 23:25
Been trying to crossfade 2 images using states and transitions but can't seem to find my newbie error. Upon clicking the image fades correctly the 1st time then from then from then on fails. Here is the code. Anyone see my error(s)

Item {
anchors.fill: parent

states: [
State { // this will fade in rect2 and fade out rect
name: "fadeInRect2"
PropertyChanges { target: rect; opacity: 0}
PropertyChanges { target: rect2; opacity: 1}
},
State { // this will fade in rect and fade out rect2
name:"fadeOutRect2"
PropertyChanges { target: rect;opacity:1}
PropertyChanges { target: rect2;opacity:0}
}
]

transitions: [
Transition {
to: "fadeInRect2"
ParallelAnimation {
NumberAnimation { properties: "opacity"; from:1;to:0;easing.type: Easing.InOutQuad; duration: 2500 }
NumberAnimation { properties: "opacity"; from:0;to:1;easing.type: Easing.InOutQuad; duration: 2500 }
}
onRunningChanged: {
if(!running) busyIndicator.running=false;
}
},
Transition {
to: "fadeOutRect2"
ParallelAnimation {
NumberAnimation { properties: "opacity";from:0;to:1;easing.type: Easing.InOutQuad; duration: 2500 }
NumberAnimation { properties: "opacity";from:1;to:0;easing.type:Easing.InOutQuad; duration:2500}
}
onRunningChanged: {
if(!running) busyIndicator.running=false;
}
}
]

Image {
id: rect2
smooth: true
opacity: 0
anchors.fill: parent
onStatusChanged: {
if(rect2.status===Image.Ready) {
console.log('rect2 img is ready');
fader.state='fadeInRect2';
console.log('doing fadeInRect2');
}
}
}

Image {
id: rect
smooth: true
anchors.fill: parent
opacity: 1

onStatusChanged: {
if(rect.status===Image.Ready) {
console.log('rect img is ready');
fader.state='fadeOutRect2';
console.log('doing fadeOutRect2');
}
}
}

function toggle() {
busyIndicator.running=true;

if(!rect2.opacity) { // load to the rect that has 0 opacity
rect2.source="../../assets/red.jpg"
}
else {
rect.source="../../assets/green.jpg"
}
}
}

wysota
9th September 2016, 08:25
This code doesn't make much sense, if you ask me. I can't even get it to work.

If you want to fade two images using states then this works:

import QtQuick 2.4

Item {
anchors.fill: parent

states: [
State { // this will fade in rect2 and fade out rect
name: "fadeInRect2"
PropertyChanges { target: rect; opacity: 0}
PropertyChanges { target: rect2; opacity: 1}
},
State { // this will fade in rect and fade out rect2
name:"fadeOutRect2"
PropertyChanges { target: rect;opacity:1}
PropertyChanges { target: rect2;opacity:0}
}
]

transitions: [
Transition {
NumberAnimation { property: "opacity"; easing.type: Easing.InOutQuad; duration: 2500 }
}
]

Image {
id: rect2
smooth: true
anchors.fill: parent
source: "/usr/share/icons/oxygen/256x256/apps/yakuake.png"
}

Image {
id: rect
smooth: true
anchors.fill: parent
source: "/usr/share/icons/oxygen/256x256/apps/showfoto.png"
}

state: "fadeInRect2"

MouseArea {
anchors.fill: parent
onClicked: {
parent.state = parent.state == "fadeInRect2" ? "fadeOutRect2" : "fadeInRect2"
}
}
}

sysv
9th September 2016, 16:15
Thanks for your reply but the image sources are from a external url and are not known till runtime. the images are for a background for a music player and change with every song. so what i wanted to to is crossfade at the end of every song.

the code i posted was what i had been testing with the function toggler should have the url passed to it then it should load to either the rect or rect2 depending on which image was transparent . it works the 1st time then fails from then on. i can't see why the state only triggers the 1st time. the images appear to load though.

sysv
9th September 2016, 21:54
ok so i made a few changes but the code is still not working correctly.

click once fades correctly to green
click 2nd time fades correctly to red

click 3 or more times loading indicator comes on and stays on but no fade

Main.qml

import VPlayApps 1.0
import QtQuick 2.5
import QtQuick.Controls 2.0
import "common"

App {

width: 640
height: 480
color: 'black'
menuBarVPlayEnabled: false

ButtonClicker{id:button}
Fader{id:fader}
BusyIndicator{id:busyIndicator}

}


BusyIndicator.qml

import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4

BusyIndicator {
running: false
scale: .2
anchors.centerIn: parent
style: BusyIndicatorStyle {
indicator: Image {
visible: busyIndicator.running
source: "../../assets/loader.gif"
RotationAnimator on rotation {
running: busyIndicator.running
loops: Animation.Infinite
duration: 2000
from: 0 ; to: 360
alwaysRunToEnd: false
}
}
}
}


ButtonClicker.qml

import QtQuick 2.5
import QtQuick.Controls 2.0

Button {
width:text.width
height:40
text: "Start Fader"
z:3
anchors.left: parent.left
anchors.top:parent.top
anchors.topMargin: 5
anchors.leftMargin: 5
onClicked: {
fader.toggle();
}
}


Fader.qml

import QtQuick 2.5
import QtQuick.Controls 2.0

Item {
anchors.fill: parent

states: [
State { // this will fade in rect2 and fade out rect
name: "fadeInRect2"
PropertyChanges { target: rect; opacity: 0}
PropertyChanges { target: rect2; opacity: 1}
},
State { // this will fade in rect and fade out rect2
name:"fadeOutRect2"
PropertyChanges { target: rect;opacity:1}
PropertyChanges { target: rect2;opacity:0}
}
]

transitions: [
Transition {
NumberAnimation { properties: "opacity";easing.type: Easing.InOutQuad; duration: 2500 }
onRunningChanged: {
if(!running) busyIndicator.running=false; // stop the loading indicator
}
}
]

Image {
id: rect2
smooth: true
opacity: 0
anchors.fill: parent

onStatusChanged: {
if(rect2.status===Image.Ready) {
console.log('rect2 img is ready');
fader.state='fadeInRect2';
console.log('doing fadeInRect2');
}
}
}

Image {
id: rect
smooth: true
opacity: 1
anchors.fill: parent

onStatusChanged: {
if(rect.status===Image.Ready) { // start the fade when img is ready
console.log('rect img is ready');
fader.state='fadeOutRect2';
console.log('doing fadeOutRect2');
}
}
}

function toggle() {
busyIndicator.running=true; // start the loading indicator

if(!rect2.opacity) { // load to the rect that has 0 opacity
rect2.source="https://placehold.it/640x480/008000"; //green rect
}
else {
rect.source="https://placehold.it/640x480/ff0000"; //red rect
}
}
}

Added after 1 25 minutes:

ok finally i fixed it problem was in the toggle function like bellow

function toggle() {
busyIndicator.running=true; // start the loading indicator

if(!rect2.opacity) { // load to the rect that has 0 opacity
rect2.source=""; // clr old
rect2.source="https://placehold.it/640x480/008000"; //green rect
}
else {
rect.source=""; // clr old
rect.source="https://placehold.it/640x480/ff0000"; //red rect
}
}

wysota
12th September 2016, 12:52
Thanks for your reply but the image sources are from a external url and are not known till runtime.
It completely doesn't matter. You can put any image urls you want, just make sure you assign them to the rect and rect2.

Your current code is very ugly - it is very imperative and the problem is easy to solve without any imperative code.