我想在 JavaScript 中创建一个延迟函数,它需要一个延迟时间量的参数,这样我就可以使用它在我的 QML 应用程序中的 JavaScript 行执行之间引入延迟。它可能看起来像这样:
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.");
});
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
。 问题在于,即使触发一次,回调仍会保持与
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
的函数来动态创建和调用这个
Timer
对象。注意答案假设 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);
另请参阅:
https://community.esri.com/groups/appstudio/blog/2019/05/22/ecmascript-7-settimeout-and-arrow-functions在需要时添加计时器的 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');
}
和https://stackoverflow.com/a/50224584/3220983... 将此文件/组件添加到您的项目中:
调度程序.qml
import QtQuick 2.0
Timer {
id: timer
property var _cbFunc: null
property int _asyncTimeout: 250
// Execute the callback asynchonously (ommiting a specific delay time)
function async( cbFunc )
{ delay( cbFunc, _asyncTimeout ) }
// Start the timer and execute the provided callback ONCE after X ms
function delay( cbFunc, milliseconds )
{ _start( cbFunc, milliseconds, false ) }
// Start the timer and execute the provided callback repeatedly every X ms
function periodic( cbFunc, milliseconds )
{ _start( cbFunc, milliseconds, true ) }
function _start( cbFunc, milliseconds, isRepeat ) {
if( cbFunc === null ) return
cancel()
_cbFunc = cbFunc
timer.interval = milliseconds
timer.repeat = isRepeat
timer.triggered.connect( cbFunc )
timer.start()
}
// Stop the timer and unregister the cbFunc
function cancel() {
if( _cbFunc === null ) return
timer.stop()
timer.triggered.disconnect( _cbFunc )
_cbFunc = null
}
}
然后,在另一个组件中实现,例如:
...
Scheduler { id: scheduler; }
scheduler.delay( function(){ console.log('Delayed'); }, 3000 );
您可以使用此处所示的匿名函数,或者回调到命名函数。如果您不太关心确切的时间,请使用简单的
async
以非阻塞方式触发代码。请注意,虽然对“异步”回调使用 0 毫秒超时很诱人(就像使用 C++ QTimer 一样),但这对于 QML Timer 来说并不是正确的方法!这些计时器似乎不会在优先考虑屏幕重绘的事件循环中对事件进行排队。因此,如果您的目标是推迟给定操作以首先实现“即时”UI 更改,则需要调高延迟间隔,如下所示。 使用 0ms 通常会导致代码在重绘之前触发。
请注意,这些“调度程序”实例之一只能在一个给定的时间间隔内绑定到一个回调函数。 如果您需要“重叠”延迟事件,则需要多个实例。
void QmlUtils::singleShot(int msec, QJSValue callback)
{
QTimer::singleShot(msec, this, [callback] () mutable {
if (callback.isCallable())
callback.call();
});
}
然后在 QML 中调用它,无论您身在何处:
qmlUtils.singleShot(5000, () => console.log("Hello!"))
完成。
如果需要,您可以使用
this,甚至无需编写它。只需将其暴露给 QML:
ctx->setContextProperty("lqtUtils", new lqt::QmlUtils(qApp));
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)
}
}