如何在 QML 中创建延迟函数?
How to create delay function in QML?
我想在 javascript 中创建一个延迟函数,它采用延迟时间参数,这样我就可以使用它在我的 JavaScript 行的执行之间引入延迟QML 应用程序。它可能看起来像这样:
function delay(delayTime) {
// code to create delay
}
我需要函数体 delay()
。请注意,JavaScript 的 setTimeout()
在 QML 中不起作用。
正如您问题的评论中所建议的那样,Timer 组件是一个很好的解决方案。
function Timer() {
return Qt.createQmlObject("import QtQuick 2.0; Timer {}", root);
}
timer = new Timer();
timer.interval = 1000;
timer.repeat = true;
timer.triggered.connect(function () {
print("I'm triggered once every second");
})
timer.start();
以上是我目前的使用方式,下面是我可能如何实现您问题中的示例。
function delay(delayTime) {
timer = new Timer();
timer.interval = delayTime;
timer.repeat = false;
timer.start();
}
(什么都不做;继续阅读)
虽然您正在寻找它的确切实现方式表明您正在寻找它以 阻止 直到程序的下一行执行。但这不是解决此问题的好方法,因为它还会阻止程序中的 其他所有内容 ,因为 JavaScript 仅在单个执行线程中运行。
另一种方法是传递回调。
function delay(delayTime, cb) {
timer = new Timer();
timer.interval = delayTime;
timer.repeat = false;
timer.triggered.connect(cb);
timer.start();
}
这将允许您这样使用它。
delay(1000, function() {
print("I am called one second after I was started.");
});
希望对您有所帮助!
编辑:以上内容假设您在一个单独的 JavaScript 文件中工作,稍后您将其导入到您的 QML 文件中。要直接在 QML 文件中执行等效操作,您可以这样做。
import QtQuick 2.0
Rectangle {
width: 800
height: 600
color: "brown"
Timer {
id: timer
}
function delay(delayTime, cb) {
timer.interval = delayTime;
timer.repeat = false;
timer.triggered.connect(cb);
timer.start();
}
Rectangle {
id: rectangle
color: "yellow"
anchors.fill: parent
anchors.margins: 100
opacity: 0
Behavior on opacity {
NumberAnimation {
duration: 500
}
}
}
Component.onCompleted: {
print("I'm printed right away..")
delay(1000, function() {
print("And I'm printed after 1 second!")
rectangle.opacity = 1
})
}
}
不过,我不相信这是解决您实际问题的方法;要延迟动画,您可以使用 PauseAnimation.
你可以使用 QtTest
import QtTest 1.0
import QtQuick 2.9
ApplicationWindow{
id: window
TestEvent {
id: test
}
function delay_ms(delay_time) {
test.mouseClick(window, 0, 0, Qt.NoButton, Qt.NoModifier, delay_time)
}
}
Marcus 的回答可以解决问题,但是有一个大问题。
问题是回调即使在触发一次后仍保持连接到 triggered
信号。这意味着如果您再次使用该延迟功能,计时器将再次触发之前连接的 all 回调。所以你应该在触发后断开回调。
这是我的延时功能增强版:
Timer {
id: timer
function setTimeout(cb, delayTime) {
timer.interval = delayTime;
timer.repeat = false;
timer.triggered.connect(cb);
timer.triggered.connect(function release () {
timer.triggered.disconnect(cb); // This is important
timer.triggered.disconnect(release); // This is important as well
});
timer.start();
}
}
...
timer.setTimeout(function(){ console.log("triggered"); }, 1000);
这是另一个变体,它利用 Component
对象来容纳 Timer
对象。
然后我们实现一个setTimeout
look-a-like函数来动态创建和调用这个Timer
对象。
N.B。答案假定 Qt5.12.x 包含 ECMAScript 7(因此包含 ECMAScript 6)以利用参数快捷方式、剩余参数和传播语法:
function setTimeout(func, interval, ...params) {
return setTimeoutComponent.createObject(app, { func, interval, params} );
}
function clearTimeout(timerObj) {
timerObj.stop();
timerObj.destroy();
}
Component {
id: setTimeoutComponent
Timer {
property var func
property var params
running: true
repeat: false
onTriggered: {
func(...params);
destroy();
}
}
}
在下面的代码片段中,我们将在从现在开始的 0-1000 毫秒之间的随机时间延迟中调用 console.log(31)
、console.log(32)
、console.log(33)
。
console.log("Started");
setTimeout(console.log, Math.floor(1000 * Math.random()), 31);
setTimeout(console.log, Math.floor(1000 * Math.random()), 32);
setTimeout(console.log, Math.floor(1000 * Math.random()), 33);
Bumsik Kim 的答案很好,这个答案稍微改变了它,以便可以重复使用计时器,然后在需要时停止并重新使用。
在需要时添加的计时器 QML。
// Allow outside access (optional)
property alias timer: timer
Timer {
id: timer
// Start the timer and execute the provided callback on every X milliseconds
function startTimer(callback, milliseconds) {
timer.interval = milliseconds;
timer.repeat = true;
timer.triggered.connect(callback);
timer.start();
}
// Stop the timer and unregister the callback
function stopTimer(callback) {
timer.stop();
timer.triggered.disconnect(callback);
}
}
可以按如下方式使用。
timer.startTimer(Foo, 1000); // Run Foo every 1 second
timer.stopTimer(Foo); // Stop running Foo
timer.startTimer(Bar, 2000); // Run Bar every 2 seconds
timer.stopTimer(Bar); // Stop running Bar
function Foo() {
console.log('Executed Foo');
}
function Bar() {
console.log('Executed Bar');
}
这是我对之前答案的持续改进 and 。
将此文件/组件添加到您的项目中:
Scheduler.qml
import QtQuick 2.0
Timer {
id: timer
// Execute the callback asynchronously
function async(callback)
{ _start(callback, 0, false); }
// Start the timer and execute the provided callback ONCE after X milliseconds
function delay(callback, milliseconds)
{ _start(callback, milliseconds, false); }
// Start the timer and execute the provided callback on every X milliseconds
function periodic(callback, milliseconds)
{ _start(callback, milliseconds, true); }
function _start(callback, milliseconds, isRepeat) {
timer.interval = milliseconds;
timer.repeat = isRepeat;
timer.triggered.connect(callback);
timer.start();
}
// Stop the timer and unregister the callback
function cancel(callback) {
timer.stop();
timer.triggered.disconnect(callback);
}
}
然后,在另一个组件中实现,如:
...
Scheduler { id: scheduler; }
scheduler.delay( function(){ console.log('Delayed'); }, 3000 );
您可以使用此处显示的匿名函数,或者回调到命名函数,这使得以后能够使用 cancel
方法。请注意,async
将尽快启动(当应用程序有时间时),而不会阻止您的调用代码块的执行。
如果您希望实例化多个定时器,定时器将根据“调度程序”独立分组/管理。
我想在 javascript 中创建一个延迟函数,它采用延迟时间参数,这样我就可以使用它在我的 JavaScript 行的执行之间引入延迟QML 应用程序。它可能看起来像这样:
function delay(delayTime) {
// code to create delay
}
我需要函数体 delay()
。请注意,JavaScript 的 setTimeout()
在 QML 中不起作用。
正如您问题的评论中所建议的那样,Timer 组件是一个很好的解决方案。
function Timer() {
return Qt.createQmlObject("import QtQuick 2.0; Timer {}", root);
}
timer = new Timer();
timer.interval = 1000;
timer.repeat = true;
timer.triggered.connect(function () {
print("I'm triggered once every second");
})
timer.start();
以上是我目前的使用方式,下面是我可能如何实现您问题中的示例。
function delay(delayTime) {
timer = new Timer();
timer.interval = delayTime;
timer.repeat = false;
timer.start();
}
(什么都不做;继续阅读)
虽然您正在寻找它的确切实现方式表明您正在寻找它以 阻止 直到程序的下一行执行。但这不是解决此问题的好方法,因为它还会阻止程序中的 其他所有内容 ,因为 JavaScript 仅在单个执行线程中运行。
另一种方法是传递回调。
function delay(delayTime, cb) {
timer = new Timer();
timer.interval = delayTime;
timer.repeat = false;
timer.triggered.connect(cb);
timer.start();
}
这将允许您这样使用它。
delay(1000, function() {
print("I am called one second after I was started.");
});
希望对您有所帮助!
编辑:以上内容假设您在一个单独的 JavaScript 文件中工作,稍后您将其导入到您的 QML 文件中。要直接在 QML 文件中执行等效操作,您可以这样做。
import QtQuick 2.0
Rectangle {
width: 800
height: 600
color: "brown"
Timer {
id: timer
}
function delay(delayTime, cb) {
timer.interval = delayTime;
timer.repeat = false;
timer.triggered.connect(cb);
timer.start();
}
Rectangle {
id: rectangle
color: "yellow"
anchors.fill: parent
anchors.margins: 100
opacity: 0
Behavior on opacity {
NumberAnimation {
duration: 500
}
}
}
Component.onCompleted: {
print("I'm printed right away..")
delay(1000, function() {
print("And I'm printed after 1 second!")
rectangle.opacity = 1
})
}
}
不过,我不相信这是解决您实际问题的方法;要延迟动画,您可以使用 PauseAnimation.
你可以使用 QtTest
import QtTest 1.0
import QtQuick 2.9
ApplicationWindow{
id: window
TestEvent {
id: test
}
function delay_ms(delay_time) {
test.mouseClick(window, 0, 0, Qt.NoButton, Qt.NoModifier, delay_time)
}
}
Marcus 的回答可以解决问题,但是有一个大问题。
问题是回调即使在触发一次后仍保持连接到 triggered
信号。这意味着如果您再次使用该延迟功能,计时器将再次触发之前连接的 all 回调。所以你应该在触发后断开回调。
这是我的延时功能增强版:
Timer {
id: timer
function setTimeout(cb, delayTime) {
timer.interval = delayTime;
timer.repeat = false;
timer.triggered.connect(cb);
timer.triggered.connect(function release () {
timer.triggered.disconnect(cb); // This is important
timer.triggered.disconnect(release); // This is important as well
});
timer.start();
}
}
...
timer.setTimeout(function(){ console.log("triggered"); }, 1000);
这是另一个变体,它利用 Component
对象来容纳 Timer
对象。
然后我们实现一个setTimeout
look-a-like函数来动态创建和调用这个Timer
对象。
N.B。答案假定 Qt5.12.x 包含 ECMAScript 7(因此包含 ECMAScript 6)以利用参数快捷方式、剩余参数和传播语法:
function setTimeout(func, interval, ...params) {
return setTimeoutComponent.createObject(app, { func, interval, params} );
}
function clearTimeout(timerObj) {
timerObj.stop();
timerObj.destroy();
}
Component {
id: setTimeoutComponent
Timer {
property var func
property var params
running: true
repeat: false
onTriggered: {
func(...params);
destroy();
}
}
}
在下面的代码片段中,我们将在从现在开始的 0-1000 毫秒之间的随机时间延迟中调用 console.log(31)
、console.log(32)
、console.log(33)
。
console.log("Started");
setTimeout(console.log, Math.floor(1000 * Math.random()), 31);
setTimeout(console.log, Math.floor(1000 * Math.random()), 32);
setTimeout(console.log, Math.floor(1000 * Math.random()), 33);
Bumsik Kim 的答案很好,这个答案稍微改变了它,以便可以重复使用计时器,然后在需要时停止并重新使用。
在需要时添加的计时器 QML。
// Allow outside access (optional)
property alias timer: timer
Timer {
id: timer
// Start the timer and execute the provided callback on every X milliseconds
function startTimer(callback, milliseconds) {
timer.interval = milliseconds;
timer.repeat = true;
timer.triggered.connect(callback);
timer.start();
}
// Stop the timer and unregister the callback
function stopTimer(callback) {
timer.stop();
timer.triggered.disconnect(callback);
}
}
可以按如下方式使用。
timer.startTimer(Foo, 1000); // Run Foo every 1 second
timer.stopTimer(Foo); // Stop running Foo
timer.startTimer(Bar, 2000); // Run Bar every 2 seconds
timer.stopTimer(Bar); // Stop running Bar
function Foo() {
console.log('Executed Foo');
}
function Bar() {
console.log('Executed Bar');
}
这是我对之前答案的持续改进
将此文件/组件添加到您的项目中:
Scheduler.qml
import QtQuick 2.0
Timer {
id: timer
// Execute the callback asynchronously
function async(callback)
{ _start(callback, 0, false); }
// Start the timer and execute the provided callback ONCE after X milliseconds
function delay(callback, milliseconds)
{ _start(callback, milliseconds, false); }
// Start the timer and execute the provided callback on every X milliseconds
function periodic(callback, milliseconds)
{ _start(callback, milliseconds, true); }
function _start(callback, milliseconds, isRepeat) {
timer.interval = milliseconds;
timer.repeat = isRepeat;
timer.triggered.connect(callback);
timer.start();
}
// Stop the timer and unregister the callback
function cancel(callback) {
timer.stop();
timer.triggered.disconnect(callback);
}
}
然后,在另一个组件中实现,如:
...
Scheduler { id: scheduler; }
scheduler.delay( function(){ console.log('Delayed'); }, 3000 );
您可以使用此处显示的匿名函数,或者回调到命名函数,这使得以后能够使用 cancel
方法。请注意,async
将尽快启动(当应用程序有时间时),而不会阻止您的调用代码块的执行。
如果您希望实例化多个定时器,定时器将根据“调度程序”独立分组/管理。