So I try:
Rectangle {
x: 617
y: 450
Image {
id: rect
source: "buttons/GO/GO!-norm.png"
smooth: true
opacity: 1
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true //this line will enable mouseArea.containsMouse
onClicked: Qt.quit()
}
states: [
State {
name: "mouse-over"; when: mouseArea.containsMouse
PropertyChanges { target: rect; scale: 0.95; opacity: 0; }
PropertyChanges { target: rect2; scale: 0.95; opacity: 1}
PropertyChanges { target: rect3; scale: 0.95; opacity: 0}
},
State {
name: "mouse-down"; when: mouseArea.pressedButtons
PropertyChanges { target: rect; scale: 0.95; opacity: 0; }
PropertyChanges { target: rect2; scale: 0.95; opacity: 0}
PropertyChanges { target: rect3; scale: 0.95; opacity: 1}
}
]
transitions: Transition {
NumberAnimation { properties: "scale, opacity"; easing.type: Easing.InOutQuad; duration: 500 }
}
}
Image {
id: rect2
source: "buttons/GO/GO!-over.png"
smooth: true
opacity: 0
anchors.fill: rect
}
Image {
id: rect3
source: "buttons/GO/GO!-down.png"
smooth: true
opacity: 0
anchors.fill: rect
}
}
but it works only in over\out states... How to make my button have 3 states?
I'm not entirely sure if this is what happens but it's possible: When you mouseover the image, its opacity gets set to 0. The documentation says that:
Changing opacity affects also the child items of the Item.
If an item's opacity is set to 0, the item will no longer receive mouse events.
Thus, when you mouseover, the rect.opacity is set to 0, mouseArea stops receiving mouse events and the mouseArea.pressedButtons condition is never fulfilled. You can probably avoid this by making mouseArea a sibling of the Image and not its child item. Use an Item or Rectangle as the parent item.
Related
With Qt Quick, I created a custom button which looks like that:
This button also contains several states (default, hover, pressed), and the transition between each states is animated. I found a way to animate each properties easily with the Qt Quick engine, except for the image one. Indeed, I want to animate the image transition, by performing a crossfade between states.
However I couldn't found a such animator for images. The only way I found was to add 3 images to my button, one for each states, and to animate their respective opacity.
Below is the code for my buttons:
Button
{
property bool hoveredBtn: false
property bool pressedBtn: false
id: btAnimStateDemo
height: 40
anchors.right: parent.right
anchors.rightMargin: 5
anchors.left: parent.left
anchors.leftMargin: 5
anchors.top: parent.top
anchors.topMargin: 290
state: "DEFAULT"
// the button background
background: Rectangle
{
id: btAnimStateDemoBg
anchors.fill: parent
}
// the button text
Text
{
id: btAnimStateDemoText
text: qsTr("A button showing animated states (default, hovered, pressed)")
renderType: Text.NativeRendering
font.bold: true
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
anchors.fill: parent
}
Image
{
id: btAnimStateDemoDefaultImage
width: 30
height: 30
anchors.left: parent.left
anchors.leftMargin: 5
anchors.bottom: parent.bottom
anchors.bottomMargin: 5
anchors.top: parent.top
anchors.topMargin: 5
opacity: 1.0
source: "Resources/Palette.svg"
}
Image
{
id: btAnimStateDemoHoverImage
width: 30
height: 30
anchors.left: parent.left
anchors.leftMargin: 5
anchors.bottom: parent.bottom
anchors.bottomMargin: 5
anchors.top: parent.top
anchors.topMargin: 5
opacity: 0.0
source: "Resources/Smile.svg"
}
Image
{
id: btAnimStateDemoPressedImage
width: 30
height: 30
anchors.left: parent.left
anchors.leftMargin: 5
anchors.bottom: parent.bottom
anchors.bottomMargin: 5
anchors.top: parent.top
anchors.topMargin: 5
opacity: 0.0
source: "Resources/Woman.svg"
}
// the component state array
states:
[
State
{
name: "DEFAULT"
PropertyChanges { target: btAnimStateDemoBg; color: "green"}
PropertyChanges { target: btAnimStateDemoBg; radius: 4}
PropertyChanges { target: btAnimStateDemoDefaultImage; opacity: 1.0}
PropertyChanges { target: btAnimStateDemoHoverImage; opacity: 0.0}
PropertyChanges { target: btAnimStateDemoPressedImage; opacity: 0.0}
},
State
{
name: "HOVERED"
PropertyChanges { target: btAnimStateDemoBg; color: "red"}
PropertyChanges { target: btAnimStateDemoBg; radius: 10}
PropertyChanges { target: btAnimStateDemoDefaultImage; opacity: 0.0}
PropertyChanges { target: btAnimStateDemoHoverImage; opacity: 1.0}
PropertyChanges { target: btAnimStateDemoPressedImage; opacity: 0.0}
},
State
{
name: "PRESSED"
PropertyChanges { target: btAnimStateDemoBg; color: "blue"}
PropertyChanges { target: btAnimStateDemoBg; radius: 15}
PropertyChanges { target: btAnimStateDemoDefaultImage; opacity: 0.0}
PropertyChanges { target: btAnimStateDemoHoverImage; opacity: 0.0}
PropertyChanges { target: btAnimStateDemoPressedImage; opacity: 1.0}
}
]
// the matching transitions between states
transitions:
[
Transition
{
from: "*"; to: "DEFAULT"
ColorAnimation { property: "color"; easing.type: Easing.Linear; duration: 1000 }
NumberAnimation { properties: "radius, opacity"; easing.type: Easing.Linear; duration: 1000 }
},
Transition
{
from: "*"; to: "HOVERED"
ColorAnimation { property: "color"; easing.type: Easing.Linear; duration: 1000 }
NumberAnimation { properties: "radius, opacity"; easing.type: Easing.Linear; duration: 1000 }
},
Transition
{
from: "*"; to: "PRESSED"
ColorAnimation { property: "color"; easing.type: Easing.Linear; duration: 1000 }
NumberAnimation { properties: "radius, opacity"; easing.type: Easing.Linear; duration: 1000 }
}
]
// the mouse area which will apply the correct state in relation to the current mouse status
MouseArea
{
anchors.fill: parent
hoverEnabled: true
onEntered: {btAnimStateDemo.state = "HOVERED"; btAnimStateDemo.hoveredBtn = true;}
onExited: {btAnimStateDemo.state = btAnimStateDemo.pressedBtn ? "PRESSED" : "DEFAULT"; btAnimStateDemo.hoveredBtn = false;}
onPressed: {btAnimStateDemo.state = "PRESSED"; btAnimStateDemo.pressedBtn = true;}
onReleased: {btAnimStateDemo.state = btAnimStateDemo.hoveredBtn ? "HOVERED" : "DEFAULT"; btAnimStateDemo.pressedBtn = false;}
}
}
The above code works well, and reaches the purpose I planned, but is a little complicated from my point of view. It would be wonderful if an animator like NumberAnimation or ColorAnimation would exist for the images, but I found none.
So my question is: Is there a simpler way to animate an image transition between component states than my above proposed solution? Do Qt Quick propose an animator to reach a such purpose?
Create a SpriteSheet that assigns states to each of the three frames then set the interpolate property to true to have it transition between the images.
Sprite Animations with SpriteSequence
SpriteSequence demonstrates using a sprite sequence to draw an animated and interactive bear. The SpriteSequence object defines five different sprites. The bear is initially in a still state:
Sprite{
name: "still"
source: "content/BearSheet.png"
frameCount: 1
frameWidth: 256
frameHeight: 256
frameDuration: 100
to: {"still":1, "blink":0.1, "floating":0}
}
When the scene is clicked, an animation sets the sprite sequence to the falling states and animates the bear's y property.
SequentialAnimation {
id: anim
ScriptAction { script: image.goalSprite = "falling"; }
NumberAnimation { target: image; property: "y"; to: 480; duration: 12000; }
ScriptAction { script: {image.goalSprite = ""; image.jumpTo("still");} }
PropertyAction { target: image; property: "y"; value: 0 }
}
At the end of the animation the bear is set back to its initial state.
Example of Qml - Flipable:
import QtQuick 2.0
Flipable {
id: flipable
width: 240
height: 240
property bool flipped: false
front: Rectangle { width: 200; height: 200; color: 'red'; anchors.centerIn: parent }
back: Rectangle { width: 200; height: 200; color: 'blue'; anchors.centerIn: parent }
transform: Rotation {
id: rotation
origin.x: flipable.width/2
origin.y: flipable.height/2
axis.x: 0; axis.y: 1; axis.z: 0 // set axis.y to 1 to rotate around y-axis
angle: 0 // the default angle
}
states: State {
name: "back"
PropertyChanges { target: rotation; angle: 180 }
when: flipable.flipped
}
transitions: Transition {
NumberAnimation { target: rotation; property: "angle"; duration: 4000 }
}
MouseArea {
anchors.fill: parent
onClicked: flipable.flipped = !flipable.flipped
}
}
This example is running good but, if I use this code, Flipable doesn't run:
MouseArea {
anchors.fill: parent
onClicked: {
flipable.flipped = true;
flipable.flipped = false;
}
}
I think the animation conflicts when I first make the flipped property is true then false. Whereas I want flipable open and then close.
The problem is that you set the property flipped back to false before the flip animation even started.
If you want the full open/close animation, you have to wait for the "open" animation to finish before starting the "close" animation:
transitions: Transition {
id: transition
onRunningChanged: {
if (!running && flipable.flipped) {
flipable.flipped = false;
}
}
NumberAnimation { target: rotation; property: "angle"; duration: 4000 }
}
MouseArea {
anchors.fill: parent
onClicked: {
if (!transition.running) {
flipable.flipped = true;
}
}
}
I have an image that i need to show for few seconds. How to do it in QML ?
Does anyone has an an example ?
i have this one with state but its doest not appear . I need also to make ir repetitive
Item {
id: myimageanimation
x:0
y:0
z:2000
Image {
id: rect
x: 293
y: 242
source: "assets/ic_sound_popup_off.png"
}
states: [
State {
name: "actif"
PropertyChanges {
target: rect
visible:true
}
},
State {
name:"inactif"
PropertyChanges {
target:rect
visible : false
}
}
]
transitions: [
Transition {
NumberAnimation {
property: "visible"
duration:2000
easing.type: Easing.InOutQuad
}
}
]
You can use an PropertyAnimation on visible
Window {
id: root
visible: true
width: 1200
height: 1000
Image {
id: rect
anchors.fill: parent
source: 'qrc:/Pics/mypic.png'
}
PropertyAnimation {
running: true
target: rect
property: 'visible'
to: false
duration: 5000 // turns to false after 5000 ms
}
}
Or, as #ddriver mentioned, use the Timer-Object, e.g. like this:
Window {
id: root
visible: true
width: 1200
height: 1000
Image {
id: rect
anchors.fill: parent
source: 'qrc:/Pics/mypic.png'
}
Timer {
interval: 5000 // triggers every 5000 ms
onTriggered: rect.visible = false
running: true
}
}
You can also use the Animation to fade it away:
Window {
id: root
visible: true
width: 1200
height: 1000
Rectangle {
id: rect
anchors.fill: parent
color: 'red'
visible: opacity > 0
}
SequentialAnimation {
running: true
PauseAnimation {
duration: 4000 // Wait for 4000ms
}
NumberAnimation {
target: rect
property: 'opacity'
to: 0
duration: 1000 // Then fade away for 1000ms
}
}
}
With the Timer, you can use a Behavior on opacity to achive the same.
I am trying to animate the margin value change with animation in QML, but i cant. The animation is not working
This is my state
State {
name: "up"
PropertyChanges {
target: drag_line
anchors.topMargin: 50
}
And in the transition i tried
transitions: [
Transition {
to: "up"
NumberAnimation { properties: "margin" ;easing.type: Easing.InOutQuad;duration: 300 }
}
]
I also tried the number animation but it also didn't work. Is there any way, am i doing something wrong
The property is not margin but anchors.topMargin
This is my working example:
ApplicationWindow {
visible: true
width: 500
height: 500
Rectangle {
width: 100
height: 100
anchors.centerIn: parent
color: "red"
Rectangle {
id: iRect
color: "blue"
width: 40
height: 40
anchors.top: parent.top
states: [State {
name: "up"
when: iMouseArea.pressed
PropertyChanges {
target: iRect
anchors.topMargin: 50
}
}]
transitions: [
Transition {
to: "up"
NumberAnimation { properties:"anchors.topMargin"; easing.type: Easing.InOutQuad;duration: 300 }
}
]
}
MouseArea{
id: iMouseArea
anchors.fill: parent
}
}
}
I would like to make an animation when mouse comes over the image, but NOT when mouse leaves the image.
Item{
width: 800
height:800
Rectangle{
id: blueRec
width: 100; height: 100; color: "blue"
MouseArea{
anchors.fill: parent
onClicked: {
im1.visible = true
im1.source = "1.png"
}
}
}
Image {
id: im1
scale: im1MouseArea.containsMouse ? 0.8 : 1.0
Behavior on scale {
NumberAnimation{
id: anim
from: 0.95
to: 1
duration: 400
easing.type: Easing.OutBounce
}
}
MouseArea{
id: im1MouseArea
hoverEnabled: true
anchors.fill: parent
}
}
}
The code above makes also animation, when mouse is leaving image.
Can someone help?
Setting the scale and then triggering an animation that alters the scale seems like an odd approach. If I were you, I'd break this out into states and set the animation to trigger on the appropriate transition.
Here's an example of how this could be done:
Image {
id: im1
states: [ "mouseIn", "mouseOut" ]
state: "mouseOut"
transitions: [
Transition {
from: "*"
to: "mouseIn"
NumberAnimation {
target: im1
properties: "scale"
from: 0.95
to: 1
duration: 400
easing.type: Easing.OutBounce
}
}
]
MouseArea{
id: im1MouseArea
hoverEnabled: true
anchors.fill: parent
onContainsMouseChanged: {
im1.state = containsMouse ? "mouseIn" : "mouseOut"
}
}
}