Reputation: 422
I want to set a 800ms delay time to run a function , so I use a timer to handle it. The code is as following.But I found, at the first time, the function runs right, it just show only one console.log("here is console....."); , but when I click it again, it shows 2 consoles, and at the third click, it shows 3 consoles, and so on...
I cannot understand why this happens, can any friends explain it for me ?
import QtQuick 2.6
import QtQuick.Window 2.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
MouseArea {
anchors.fill: parent
onClicked: {
delayTimer(800,function(){
console.log("here is console.....");
var t= Math.random();
console.log(t);
})
}
}
Timer{
id:dtimer
}
function delayTimer(delayTime, cb) {
console.log("delayTimer is starting");
dtimer.interval = delayTime;
dtimer.repeat = false;
dtimer.triggered.connect(cb);
dtimer.start();
}
}
after a few clicks, when I click it again, output is:
qml: delayTimer is starting
qml: here is console.....
qml: 0.27777099609375
qml: here is console.....
qml: 0.407012939453125
qml: here is console.....
qml: 0.60552978515625
qml: here is console.....
qml: 0.360107421875
qml: here is console.....
qml: 0.21942138671875
qml: here is console.....
qml: 0.252288818359375
qml: here is console.....
qml: 0.88134765625
qml: here is console.....
qml: 0.63092041015625
qml: here is console.....
qml: 0.5125732421875
Upvotes: 4
Views: 407
Reputation: 13691
As @w1ck3dg0ph3r pointed out, you have one function bound to the signal multiple times. However, as QML assumes, all slots are executed at the same time, there is no guaranteed order, so I think, his solution might fail, if QML decides to first disconnect your function cb
before it executes it.
There might be some precautions put in place, but they seem not to be too safe, as you can see in this example:
Button {
onClicked: {
clicked.connect(clicked)
console.log('here')
}
}
This results in a infinite loop on the first click, though it might be expected that the connection is only executed in the next run, and not already in the same run.
On the other hand this example:
Button {
onClicked: {
clicked.connect(function() {console.log('here'); clicked.connect(function() {console.log('there')})});
}
}
Here you might expect, from what we learned above, that both functions are executed in the first run, and the output is here
and there
- which is not (at least on my machine)
So the behavior when changing the bindings to a signal during the execution of those is not too well defined.
The better solution depends on your usecase. Do you want to have multiple functions bound to the signal, or always just the one?
I'd reccomend to store your function in a variable, and handle the disconnect in the onClicked
-event:
Button {
property var myCB
onClicked: {
delayTimer(delayTime, cb) {
if (myCB) dtimer.triggered.disconnect(myCB)
myCB = cb
dtimer.triggered.connect(myCB)
...
}
}
}
Like this you are able to ensure that the disconnect is performed at the right time. However if the timer is restarted by some other source, the function is still bound. If you don't want this, you need to have the function it self to ensure the disconnection.
To provide a tailored solution, you would need to add more detail on what your usecase is, and what exactly you expect.
Upvotes: 1
Reputation: 1011
You're connecting your signal to a slot every time you call delayTimer()
, so the connections accumulate and slots are invoked multiple times. I'm not familiar with qml/js, but you need to disconnect slot after timeout is triggered:
function delayTimer(delayTime, cb) {
console.log("delayTimer is starting");
dtimer.interval = delayTime;
dtimer.repeat = false;
dtimer.triggered.connect(cb);
dtimer.triggered.connect(function(){
dtimer.triggered.disconnect(cb);
});
dtimer.start();
}
Upvotes: 7