我想在JavaScript中创建一个延迟函数,它需要一个延迟的时间参数,这样我就可以在我的QML应用程序中执行JavaScript代码时引入延迟。这个函数可能会像这样:
function delay(delayTime) {
// code to create delay
}
我需要函数delay()
的函数体。请注意,JavaScript中的setTimeout()
在QML中不起作用。
我想在JavaScript中创建一个延迟函数,它需要一个延迟的时间参数,这样我就可以在我的QML应用程序中执行JavaScript代码时引入延迟。这个函数可能会像这样:
function delay(delayTime) {
// code to create delay
}
我需要函数delay()
的函数体。请注意,JavaScript中的setTimeout()
在QML中不起作用。
如评论中对您的问题所建议的,定时器组件是解决此问题的好方法。
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。
Timer
是一个不错的解决方案。 - folibis ...
timer.triggered.connect(cb);
timer.triggered.connect(function () {
timer.destroy();
});
...
- Israel Lins Albuquerquetimer = new Timer();
代替timer = Timer();
吗?new
会创建一个新对象并将其注入到Timer
中作为this
,但是你没有使用它。因此,在这里使用new
关键字似乎是多余和令人困惑的。 - Johannes Schaub - litbMarcus的答案解决了问题,但是存在一个大问题。
问题在于回调函数即使在触发一次后仍然保持连接到triggered
信号。这意味着,如果您再次使用该延迟函数,定时器将再次触发所有先前连接的回调函数。因此,应该在触发后断开回调函数的连接。
这是我增强版的延迟函数:
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);
timer.triggered.connect(function() { ... });
- manicaesar这里是另一种变化,它利用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();
}
}
}
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);
setTimeoutComponent.createObject(app, …)
中提到的 app
引用之外,这段代码写得很好。在这里传递 null
是安全的(参见)。由于对象是自我销毁的,所以垃圾回收也不是问题。 - tanius这是我对之前答案https://dev59.com/7F4b5IYBdhLWcg3w9FkI#62051450和https://dev59.com/7F4b5IYBdhLWcg3w9FkI#50224584的持续演变。
将此文件/组件添加到您的项目中:
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通常会导致代码在重绘之前触发。// 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');
}
你可以使用 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)
}
}
这应该足够了:
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));