0

I'm having trouble reading a javascript variable from QML. I know this seems easy, but this is a particular case :

I'm using canvas3D for generating lots of 3D Spheres and, as the instenciation is really long, I want to display a progress bar.

To do that, I've done this :

import "test6.js" as GLCode

Item {
id: mainview
width: 1280
height: 768
visible: true



// THE PROGRESS BAR

ProgressBar {
    id : progressBar
    anchors.centerIn: parent
    value: canvas3d.progress
    z:1
}


//THE CANVAS3D (WebGL)
Canvas3D {
    id: canvas3d
    anchors.fill: parent
    focus: true

    property double progress:0 //MY VARIABLE I WANT TO UPDATE FROM test6.js


    property var list : []

    // Emitted when one time initializations should happen
    onInitializeGL: {
        GLCode.initializeGL(canvas3d);
    }

I have a property name progress in my canvas3d which I'm trying to modify from the test6.js script

In the initializeGL(canvas3d) function I'm updating the value of progress each time I add a sphere :

for ( i = 0; i < spheresNum; i ++ ) {

    var x = list[i][0];
    var y = list[i][1];
    var z = list[i][2];
    drawSphere(x,y,z,i);
    canvas3d.progress = i/spheresNum*100;
}

Now, the problem is that I get the updated value of progress only when initializeGL() ends. Right now it's like :

Progress Bar to 0%
(Waiting for all the sphere to be instanciated)
(initializeGL() ends)
Progress Bar to 100%

Which is useless. I would prefer having the bar moving each time a sphere is created.

Do you know how can I do that ?

1 Answer 1

2

You only see 0% and 100% as progress, because the for-loop in initializeGL() is fully executed before the QML engine will respond to the changed value of canvas3d.progress and update the value of progessBar.value. The for-loop and the updating of the property binding from progessBar.value to canvas3d.progress run in the same thread.

The way to solve this problem is to call initializeGL() only for one step and then yield the CPU for updating the progress. My idea would be to use a single-shot timer that calls itself numSphere times and initialises the i-th spere in the i-th shot.

The step-wise initialisation function would be defined in test6.js as follows:

function initializeGLSphere(i) {
    var x = list[i][0];
    var y = list[i][1];
    var z = list[i][2];
    drawSphere(x,y,z,i);
}

After the instance of Canvas3d, you add the single-shot timer:

property int currentSphere = 0

Timer {
    id: timer
    repeat: false
    interval: 0
    onTriggered: {
        GLCode.initializeGLSphere(currentSphere)
        ++currentSphere
        progessBar.progress = currentSphere / GLCode.numSpheres
        if (currentSphere < GLCode.numSpheres) {
            timer.restart()
        }
    }
}

The timer is started in onInitializeGL:

onInitializeGL: timer.start()

Starting a single-shot timer means that an Event is put into the main Qt event loop. The timer fires once the timer interval expires. An interval of 0ms simply means that the timer fires and executes onTriggered as soon as possible the timer event reaches the front the event queue (loop).

In-between working on the timer events, the event queue will also give the QML engine some time to update the property binding for progressBar.progress. So, you should see quite a few intermediate progress values between 0 and 100. However, you will not see all because multiple timer events might be handled before a property-binding update happens. If you want to see more progress updates, you can simply increase the timer interval.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.