I am experimenting with using signals in my UI project. I want a button to start some processes. Whilst I was doing this I realised I didn't understand what was going on, so I wrote the below code to try to pin-point what was happening.
When run, main.qml creates some coloured boxes as controls, and some white boxes for output (made from SubOne.qml).
If you click the green box it emits signal 'broadcast', and each of the white boxes are connected to that signal.
On 'broadcast' each white box calls its function bar.
And bar starts a loop. At the end of the loop it prints the number of iterations, and changes the text property to show the same number.
The first and third white boxes do 1 loop, but the second box does enough loops to cause a noticable delay.
OK, all seems fine. As expected the three functions bar are called sequentially, and output their print sequentially. But I was suprised to find that the text properties are not updated sequentially. Instead all the bars finish and then all three text properties are updated together.
In other words in SubOne.qml line 17 doesn't take effect until ALL loops complete, but line 18 takes effect as EACH loop completes.
Can anyone tell me what is going on? Is qml doing something to optimise writing to the display? If so, can it be controlled.
Mainly, how can I make the printing and text updates happen together after EACH loop exits.
Thanks for any help.
//qml.main
import QtQuick 2.4
import QtQuick.Controls 1.3
ApplicationWindow {
visible: true
Rectangle {
Rectangle {
x: 50
y: 50
width: 50
height: 50
color: "green"
Text {
text: "Start"
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
MouseArea {
id: start
signal broadcast()
anchors.fill: parent
onClicked: broadcast();
}
}
Rectangle {
function set() {
first.thisText = "---";
second.thisText = "---";
third.thisText = "---";
}
id: reset
x: 110
y: 50
width: 50
height: 50
color: "yellow"
Text {
text: "Reset"
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
MouseArea {
anchors.fill: parent
onClicked: reset.set();
}
}
Rectangle {
id: exit
x: 170
y: 50
width: 50
height: 50
color: "red"
Text {
text: "Exit"
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
MouseArea {
anchors.fill: parent
onClicked: Qt.quit();
}
}
}
SubOne {
id: third
thisName: "third"
x: 50
y: 110
loop: 1
}
SubOne {
id: second
thisName: "second"
x: 50
y: 170
loop: 100000000
}
SubOne {
id: first
thisName: "first"
x: 50
y: 230
loop: 1
}
}
//SubOne.qml
import QtQuick 2.0
Rectangle {
id: rectangle1
property string thisName: ""
property string thisText: "nothing yet"
property int loop: 1
height:50
width:170
function bar() {
print("looping " + thisName + " with: " + loop);
for (var counter=0; counter<loop; counter+=1){
//do nothing much
}
thisText = counter;
print("looped " + thisName + " to: " + counter);
}
Text {
text: thisText
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
Connections {
target: start
onBroadcast: bar()
}
}
Here is the new code using WorkerScript, as suggested.
//SubOne.qml
import QtQuick 2.0
Rectangle {
id: rectangle1
property string thisName: ""
property string thisText: "nothing yet"
property int loop: 1
height:50
width:170
WorkerScript {
id: myWorker
source: "script.js"
onMessage: thisText = messageObject.reply
}
Text {
text: thisText
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
Connections {
target: start
onBroadcast: {
myWorker.sendMessage({'loopVal':loop, 'nameVal':thisName});
}
}
}
//script.js
WorkerScript.onMessage = function(obj) {
print("looping " + obj.nameVal + " to: " + obj.loopVal);
for (var counter=0; counter<obj.loopVal; counter+=1){
//do nothing much
}
print("finished " + obj.nameVal + " at: " + counter);
WorkerScript.sendMessage({ 'reply': counter})
}
It is worth noting that the sendMessage on line 26 of SubOne.qml does not get handled by the onMessage at line 14 of SubOne, it gets handled by the WorkerScript.onMessage at line 1 of script.js, and similarly the WorkerScript.sendMessage at line 7 of script.js is handled back in the SubOne.qml file at line 14. Also, the message sent to the new thread gets only one parameter, so to send the nameVal and loopVal I have put them in an object, created inline at line 26 of SubOne.qml
Maybe that is obvious, but it confused me for a while ;)
Its interesting that if you press 'red' during the looping, the main thread exits immediately but the second thread finishes what its doing first.
Hope this helps someone.
And thanks to BaCaRoZzo and Kuba Ober.
WorkerScriptfor a possible approach. - BaCaRoZzo