How to create delay function in QML?

前端 未结 5 588
小鲜肉
小鲜肉 2020-12-23 21:17

I would like to create a delay function in javascript that takes a parameter of amount of time to delay, so that I could use it do introduce delay between execution of javas

相关标签:
5条回答
  • 2020-12-23 21:29

    Marcus' answer does the job, but there is one big problem.

    The problem is that the callback keeps connected to triggered signal even after triggered once. This means that if you use that delay function again, the timer will triggers all callbacks connected before again. So you should disconnect the callback after triggered.

    This is my enhanced version of the delay function:

    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);
    
    0 讨论(0)
  • 2020-12-23 21:29

    you can use 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)
        }
    }
    
    0 讨论(0)
  • 2020-12-23 21:31

    As suggested in the comments to your question, the Timer component is a good solution to this.

    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();
    

    The above would be how I'm currently using it, and here's how I might have implemented the example in your question.

    function delay(delayTime) {
        timer = new Timer();
        timer.interval = delayTime;
        timer.repeat = false;
        timer.start();
    }
    

    (Which doesn't do anything; read on)

    Though the exact way you are looking for it to be implemented suggests that you are looking for it to block until the next line of your program executes. But this isn't a very good way to go about it as it would also block everything else in your program as JavaScript only runs in a single thread of execution.

    An alternative is to pass a callback.

    function delay(delayTime, cb) {
        timer = new Timer();
        timer.interval = delayTime;
        timer.repeat = false;
        timer.triggered.connect(cb);
        timer.start();
    }
    

    Which would allow you to use it as such.

    delay(1000, function() {
        print("I am called one second after I was started.");
    });
    

    Hope it helps!

    Edit: The above assumes you're working in a separate JavaScript file that you later import into your QML file. To do the equivalent in a QML file directly, you can do this.

    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
            })
        }
    }
    

    I'm not convinced that this is the solution to your actual problem however; to delay an animation, you could use PauseAnimation.

    0 讨论(0)
  • 2020-12-23 21:34

    The answer from Bumsik Kim is great, this answer changes it slightly so that the timer can be used on a repeating basis and then stopped and reused when desired.

    The QML for the timer to add where required.

    // 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);
        }
    }
    

    This can be used as follows.

    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');
    }
    
    0 讨论(0)
  • 2020-12-23 21:44

    Here's another variation which utilizes the Component object to house the Timer object.

    Then we implement a setTimeout look-a-like function to dynamically create and invoke this Timer object.

    N.B. The answer assumes Qt5.12.x which includes ECMAScript 7 (and therefore ECMAScript 6) to utilize parameter shortcuts, rest parameters and spread syntax:

        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();
                }
            }
        }
    

    In the following snippet, we will invoke console.log(31), console.log(32), console.log(33) in a random time delay between 0-1000ms from now.

    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);

    See also: https://community.esri.com/groups/appstudio/blog/2019/05/22/ecmascript-7-settimeout-and-arrow-functions

    0 讨论(0)
提交回复
热议问题