QT QML error : can't apply a state change as part of a state definition - qt

I'am struggling with the issue indicated in the title.
When trying to switch state after a custom signal made from C++ was triggered, i have this error coming from my QML script : can't apply a state change as part of a state definition.
I have barely found information about that same error on internet and i have struggling for days trying to fix this without success. Regarding the error, it's assumed that i'm trying to change state in a state definition but it's definitely not the case.
Here is a sample of my code:
Connections {
target: timer
function onTriggered() {rectangle.state = "welcomeState"}
}
Connections {
target: testBack
function onPrintDataReady() {rectangle.state = "printState"}
}
Connections {
target: boutonOui
function onPressed() {rectangle.state = "endState";testBack.printFile() }
}
Connections {
target: boutonNon
function onPressed() {rectangle.state = "endState"}
}
And the states are defined here:
states: [
State {
name: "welcomeState"
PropertyChanges {
target: logo_2
visible: false
}
PropertyChanges {
target: messageFin
visible: false
}
PropertyChanges {
target: boutonOui
visible: false
}
PropertyChanges {
target: boutonNon
visible: false
}
PropertyChanges {
target: impressionTicket
visible: false
}
},
State {
name: "printState"
PropertyChanges {
target: boutonOui
visible: true
text: qsTr("OUI")
}
PropertyChanges {
target: boutonNon
visible: true
text: "NON"
}
PropertyChanges {
target: logo_1
visible: false
}
PropertyChanges {
target: impressionTicket
visible: true
}
PropertyChanges {
target: logo_2
visible: true
}
PropertyChanges {
target: messageFin
visible: false
text: qsTr("Merci de votre visite. A bientôt.")
}
},
State {
name: "endState"
PropertyChanges {
target: logo_1
visible: false
}
PropertyChanges {
target: logo_2
visible: true
}
PropertyChanges {
target: messageFin
visible: true
text: qsTr("Merci de votre visite. A bientôt.")
anchors.verticalCenterOffset: 1
anchors.horizontalCenterOffset: 1
}
PropertyChanges {
target: boutonNon
visible: false
text: qsTr("NON")
}
PropertyChanges {
target: impressionTicket
visible: false
}
PropertyChanges {
target: boutonOui
visible: false
}
PropertyChanges {
target: timer
running: true
triggeredOnStart: false
interval: 6000
}
}
]
I can't switch to the state "printState" for the target "testBack". "testBack" is a C++ object made accessible in QML imported from C++ and so, onPrintDataReady() is a custom signal.
And the first state is "welcomeState":
Rectangle {
id: rectangle
width: 800
height: Constants.height
color: "#eb5a2d"
state: "welcomeState"
property alias messageFin: messageFin
property alias logo_1: logo_1
property bool property0: true
That transition is the only one that is not working among the 4 transition that are indicated.
Any help would be appreciated.
I made sure that the onPrintDataReady() was fired by changing the color of the rectangle instead of the state and it worked.
I tried to made the connection directly in the item "testBack" but the issue was still here.
I set the variable STATECHANGE_DEBUG to 1 but didn't give me any interesting information for my problem.
Tried the other transitions and it's all working except the one that is in testBack
And now i'm running out of idea.

Finally found a turnaroud.
Instead of going fromwelcomeState to printState through the onPrintDataReady signal, i activated a timer when printerDataReady was triggered and when receiving the trigger signal from this timer, i did the transition from welcomeState to printState so this is what i have now :
Connections {
target: timer3
function onTriggered() {testBack.waitForPrint()}
}
Connections {
target: timer2
function onTriggered() {rectangle.state = "welcomeState"}
}
Connections {
target: testBack
function onPrintDataReadyChanged() {timer.start()}
}
Connections {
target: timer
function onTriggered() {rectangle.state = "printState"}
}
Connections {
target: boutonOui
function onPressed() {rectangle.state = "endState";testBack.printFile()}
}
Connections {
target: boutonNon
function onPressed() {rectangle.state = "endState"}
}

Related

Animation problems with the property when

why doesn't animation in the left work in the first case?
qmlonline.
if you go to the second case and comment out the code with when, then the animation works. the same problem if you disable sequential animation.
this is the first case without animation
this is the second case with animation
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
id: root
property int type: 0
visible: true
width: 640
height: 480
title: qsTr("Hello World")
MouseArea {
anchors.horizontalCenter: parent.horizontalCenter
width: 50
height: 50
Rectangle { anchors.fill: parent; color: "blue" }
onClicked: {
root.type = !root.type
// stG.state = root.type ? "right" : "left" // uncomment to the second case
}
}
Rectangle {
id: switcher1
width: 50
height: 50
color: "red"
anchors.verticalCenter: parent.verticalCenter
}
Rectangle {
id: switcher2
width: 50
height: 50
color: "green"
anchors.top: switcher1.bottom
anchors.topMargin: 10
}
StateGroup {
id: stG
states: [
State {
name: "left"
when: type === 0 // comment to the second case
PropertyChanges {
target: switcher1
x: 0
}
PropertyChanges {
target: switcher2
x: 0
}
},
State {
name: "right"
when: type === 1 // comment to the second case
PropertyChanges {
target: switcher1
x: root.width - switcher1.width
}
PropertyChanges {
target: switcher2
x: root.width - switcher2.width
}
}
]
transitions: [
Transition {
to: "left"
SequentialAnimation {
NumberAnimation {
target: switcher2
property: "x"
duration: 500
}
NumberAnimation {
target: switcher1
property: "x"
duration: 500
}
}
},
Transition {
to: "right"
SequentialAnimation {
NumberAnimation {
target: switcher1
property: "x"
duration: 500
}
NumberAnimation {
target: switcher2
property: "x"
duration: 500
}
}
}
]
}
}
that's enough
I can give you a way to fix the problem, but it actually feels like there might be a bug with Qt here.
I tried adding a printout to show me what state Qt thinks it's in:
onStateChanged:
{
console.log("state: " + stG.state);
}
The output I got was this:
// First click
> state: right
// Second click
> state:
> state: left
So, what seems to be happening is that for a split second, the state enters some non-existent state and resets your x-values to 0 without using the transitions. Then the correct state gets applied, but we don't see the transition because everything is already at 0. Maybe someone smarter than me can help figure out why we switch to the bad state first.
Thankfully, there is a simple enough fix. If you make the "right" transition reversible, then it works as expected.
Transition {
to: "right"
reversible: true
...
}

QML transition changes immediately, not according to 'duration'

I have the following QML file. I wan't the rectangle myRect to slide in from the right when the root item is clicked (simplified setup). What actually happens is that myRect appears immediately when the root item is clicked.
I checked the running property on the transition and that seems to be fine. It logs true when I click the root item, and then false after 2 seconds.
Does anyone know why the x property doesn't gradually change?
import QtQuick 2.7
Item{
id: root
MouseArea{
anchors.fill: parent
onClicked: {
myRect.state = "visible"
}
}
Rectangle{
id: myRect
width: root.width
height: root.height
state: "hidden"
color: "yellow"
states: [
State {
name: "hidden"
PropertyChanges{
target: myRect
x: myRect.width
}
},
State {
name: "visible"
PropertyChanges{
target: myRect
x: 0
}
}
]
transitions: [
Transition {
NumberAnimation{
duration: 2000
}
onRunningChanged: {
console.log("Running:", running)
}
}
]
}
}
You have to indicate the property, in your case "x"
NumberAnimation{
duration: 2000
properties: "x"
}

How to manage Focus with States in my custom QML component?

I´ve created a draggable custom Component in order to manage the geometry of individual Quick Controls Components.
The componet has 2 parts:
The "Manipulator" which is a draggable and resizable Rectangle
The inner component which is in the center of the manipulator
Description of the behavior:
No focus: the default state, the Manipulator is invisible
and you can only see the inner component
Focused: When you click the component (or try to drag it) you enter
this state and the Manipulator becomes visible but you can´t access
the inner component. Disabled pressing Escape or clicking outside the component (goes to state 1)
Inner Focus: when you double click on the component The Manipulator
keeps visible and you can still still resize but the the inner
component has the main focus (for example a TextEdit now could be
editable). Disabled pessing Escape (goes to state 2) or clicking outside the component (goes to state 1)
Example of the Component when the Manipulator area is visible
The logic of this component would be similar to the logic of a folder in a Desktop Enviroment (except for resizing) The manipulator would be the folder itself and the inner component is its name.
analogy with folder
Here I post a simplified version of my manipulator, I´m sure it will help to construct an answer, (I tried a lot of variations for several hours, this is one of those not functional attempts)
FocusScope{
id: root
width: 175; height: 25;
focus: true
states: [
State {
name: "noFocus"
when: !manipulator.activeFocus && !innerComp.activeFocus
PropertyChanges {
target: innerComp
enabled: false
}
PropertyChanges {
target: manipulator
visible: false
}
},
State {
name: "focused"
when: manipulator.activeFocus
PropertyChanges {
target: innerComp
enabled: false
}
PropertyChanges {
target: manipulator
visible: true
}
},
State {
name: "innerFocus"
when: innerComp.activeFocus
PropertyChanges {
target: innerComp
enabled: true
}
PropertyChanges {
target: manipulator
visible: true
}
}
]
//visual area of manipulation (drag, redimension, etc)
MouseArea{
id: manipulator
anchors.fill: parent
onDoubleClicked: forceActiveFocus(innerComp) //go to state 3 "innerFocus"
drag.target: manipulator
Keys.onEscapePressed: forceActiveFocus(root) //I don´t think this is the correct to loose focus but I don´t know how to do that
Rectangle {
id: background
anchors.fill: parent
color: "lightsteelblue";
}
}
//Inner Component (TextField for example)
InnerComp {
id: innerComp
anchors.fill: parent
Keys.onEscapePressed: forceActiveFocus(manipulator) //return state 2 "focused"
}
}
I finally found the solution, as someone in a qt forum sugested:
Maybe reverse the dependency, i.e. make the focus depend on the state, not the state depend on the focus?
So I changed my code and now it works!
I post the solution here for those who could be interested in it (as I said this is a simplified version of the real code):
Item {
id: root
width: 175; height: 25;
states: [
State {
name: "noFocus"
PropertyChanges {
target: innerComp; enabled: false
}
PropertyChanges {
target: background; visible: false
}
PropertyChanges {
target: manipulator; focus: true
}
},
State {
name: "focused"
PropertyChanges {
target: innerComp; enabled: false
}
PropertyChanges {
target: background; visible: true
}
PropertyChanges {
target: manipulator; focus: true
}
},
State {
name: "innerFocus"
PropertyChanges {
target: innerComp; enabled: true
}
PropertyChanges {
target: background; visible: true
}
PropertyChanges {
target: manipulator; focus: true
}
}
]
state: "noFocus"
//visual area of manipulation (drag, redimension, etc)
MouseArea{
id: manipulator
anchors.fill: parent
onPressed: {
root.state = "focused"
forceActiveFocus(manipulator) //this prevents loosing focus in some especific situations
}
onDoubleClicked: root.state = "innerFocus"
Keys.onEscapePressed: root.state = "noFocus"
}
Rectangle {
id: background
anchors.fill: parent
color: "lightsteelblue";
}
//Inner Component (TextField for example)
InnerComp {
id: innerComp
anchors.fill: parent
Keys.onEscapePressed: root.state = "focused"
}
}

Qt QML state change has no effect on GUI

i have a problem with a qml state having no effect. So the state has successfully changed, but the the changes, which the statechange should change, don't happen. I'll explain the situation in detail:
i have a ListView, containing several "GameElem":
ListView
id: gameList
Component{
id: gameDelegate
GameElem{
gameID: pid
gameName: name
gameSize: size
downloadProgress: progress
downloadSpeed: speed
downloadState: filestate
}
}
model: gameListModel
delegate: gameDelegate
}
I'm emitting a signal in a class and to change the enabled buttons. So if the state is changed to "download" the "Stop download"-Button should be enabled.
onSignalNowDownloading: {
for( var i = 0; i < gameListModel.count ; i++)
{
if( gameListModel.get( i ).pid == gameID )
{
console.log( "Now downloading " + gameID )
console.log( gameListModel.get( i ).filestate + " here" ) //this line
gameListModel.setProperty( i, "filestate", "downloading")
console.log( gameListModel.get( i ).filestate + " here" ) //and this line
}
}
}
and the log in the marked lines is "resuming here" and "downloading here". so the state is changed successfully but has no effect.
some lines earlier i do a similar thing but without state. there i'm changing the progressbar and this is working properly.
onSignalDownloadProgress: {
//update list data model to make the progress bar move
for( var i = 0; i < gameListModel.count ; i++)
{
if( gameListModel.get( i ).pid == gameID)
{
gameListModel.setProperty( i, "progress", received / total)
gameListModel.setProperty( i, "speed", speed)
gameListModel.setProperty( i, "progressText", progress)
}
}
}
this is how my state looks like. just hiding or showing several buttons.
states: [
State {
name: "downloading"
PropertyChanges {
target: myBtnDownload
visible:false
}
PropertyChanges {
target: myBtnStop
visible:true
}
PropertyChanges {
target: myProgressBar
visible:true
}
PropertyChanges {
target: myTextSpeed
visible: true
}
PropertyChanges {
target: myBtnRun
visible:false
}
PropertyChanges {
target: myBtnFolder
visible:false
}
},
State {
name: "resuming"
PropertyChanges {
target: myBtnDownload
visible:false
}
PropertyChanges {
target: myBtnStop
visible:true
}
PropertyChanges {
target: myProgressBar
visible:true
}
PropertyChanges {
target: myTextSpeed
visible: false
}
PropertyChanges {
target: myBtnRun
visible:false
}
PropertyChanges {
target: myBtnFolder
visible:false
}
PropertyChanges {
target: myBtnResume
text: "resuming"
visible:true
enabled: false
}
}
]
can anyone explain me, why the progressbar changes successfully and the buttons (= states) not? maybe i can force any kind of redrawing?
thanks for your help.
Testerrrr
From the sample given, looks like you're changing model's filestate property instead of delegate's state. See this line:
gameListModel.setProperty( i, "filestate", "downloading")
Do you have GameElem.state bound to GameElem.downloadState? It's not in the code provided. And it is not clear in what component you have states...

How to stop the transition animation in QML?

There is window, its layout designed by states and transition. we know that when the state change, the transition-animation will start automatically, but when the transition animation doesn't finished, i change the state, it make troubles. just like slow in reacting; how to fix it? thank you...
it something like this :
Flickable {
id: content
anchors.fill: parent
flickableDirection: Flickable.HorizontalFlick
contentWidth: width * 2
contentHeight: height
clip: true
onFlickStarted: {
if(horizontalVelocity > 0) {
regAndFind.state = "Find"
}
else {
regAndFind.state = "Register"
}
} .......
}
states: [
State {
name: "Register"
PropertyChanges {
target: slider
x: 0
}
PropertyChanges {
target: content
contentX: 0
}
},
State {
name: "Find"
PropertyChanges {
target: slider
x: parent.width / 2
}
PropertyChanges {
target: content
contentX: parent.width
}
}
]
transitions: [
Transition {
NumberAnimation {
target: slider
property: "x"
duration: 600
}
NumberAnimation {
target: content
property: "contentX"
duration: 600
}
}
]
Read about the animation element in Qml.
Before you move to other state, you can call the Animation::stop () function to stop the animation in between. Note that it will stop the animation immediately, and the animation will have no further effect on the property values.

Resources