Blocked gui does not draw an qml item?



  • Hi,
    I have a problem with the exact timing of signals in qml.

    Problem:

    1. press on a button
    2. make iRect visible
    3. start heavyFunct() in C++ which blocks the Gui
    MouseArea {                   
           onClicked: {
                 console.log("onClicked");
                 iRect.visible = true;
         }
    
         Rectangle {
                  id: iRect
                  visible: false
                  anchors.fill: parent
                  color: "green"
    
                  onVisibleChanged: {
                         if(visible) {
                               console.log("onVisibleChanged");
                               heavyFunct();
                         }
                 }
          }
    }
    

    The signals/slots are called in the correction direction but on the screen iRect does not become visible before heavyFunct() is started. So it seems that the signals in Qml are called with the instruction in the code but not after the item was really rendered from the graphiccard.

    Is there a way to force an item to be drawn before continue with the next instruction?

    Currently I'm not able to move the heavyFunct() in a separate thread.

    What goes wrong here or how can I solve this problem?


  • Moderators

    hi @PowerNow

    after setting your Item to visible = true, you wan't to listen to the
    frameSwapped signal

    After that, your Item should be drawn on the screen.



  • @PowerNow said in Blocked gui does not draw an qml item?:

    Currently I'm not able to move the heavyFunct() in a separate thread.

    Maybe this can help you for that

    //the function you have to call from qml
    void heavyFnc(){
            for(int tt = 100000;tt>1;tt--){
                qDebug()<<tt;
            }
        }
    
    //make it static 
    static void heavyFnc(){
            for(int tt = 100000;tt>1;tt--){
                qDebug()<<tt;
            }
        }
    
    //create Q_INVOKABLE to wrap it and move it to new Qthread
        Q_INVOKABLE void doHeavyFnc(){
            QThread *t = QThread::create(heavyFnc);
            t->start();
        }
    // you have to delete *t somewhere
    


  • @PowerNow If you don't want to lock the GUI, you have to move heavyFunct() execution in another thread. There are no other option in my eyes.

    To move the function execution to another thread, there a many way to do, but the easiest way for me is using QtConcurrent:

    
    class MyClass: public QObject
     {
        Q_OBJECT
    
    ...
    private:
        void heavyFunct();
    ...
    public:
        Q_INVOKABLE void doHeavyFnc()
       {  
            if(!m_heavyInProgress.isRunning())
            {
                QtConcurrent::run(this, &MyClass::heavyFunct);
            }
        }
    ...
    private:
         QFuture<void> m_heavyInProgress;
    

    Hope this could help you.



  • Thxs to all of you!
    But as I mentioned unfortunately I can't move at the moment the heavyFunct() (its a QFramebufferobject loaded via Loader which needs a lot of memory and power) into a separat threat, currently I'm looking for a simple solution.
    @J.Hilk: Yes this works thxs! But It's an app using a Videoframbuffer (highest possible frame rate) and i think only for this button always check the frameSwapped signal does not make me feel good. Or is there a way to check it only once?

    I only want to visually show the user if he press on the button, that he have to wait and not press again during the loading of the heavyFunct(). Is there no way to force Qml to update the scenegraph and give response? The locking of the gui is not that problem.


  • Moderators

    @PowerNow said in Blocked gui does not draw an qml item?:

    Or is there a way to check it only once?

    make the slot connected to the frameSwapped signal disconnect itself when it gets called



  • @PowerNow I solved a similar issue by using a Timer.



  • @PowerNow said in Blocked gui does not draw an qml item?:

    (its a QFramebufferobject loaded via Loader

    I'm not sure to understand how this works. Is the Loader a QML Loader instance?
    Why is this loader not set asynchronous to true?

    Loader {
        source: "myHeadyComponent.qml"
        asynchronous: true
        visible: status == Loader.Ready
    }
    


  • @KroMignon Hi, I just added asynchronous: true but surprisingly no change.



  • @PowerNow This sounds very strange to me. I often use asynchronous with Loader, and it always works.

    Does your huge QML component also includes Loader?



  • @KroMignon The loaded Qml component "only" consists of a big QFramebufferObject which loads a lot of data in the graphiccard and this blocks the gui. Further Loader are not included.



  • @PowerNow Then you are either doing something wrong or using a non-threaded render loop. By default there is a dedicated render thread and a dedicated main GUI thread. Loading of data to the graphics card should happen in the render thread and won't block the GUI.

    Scene Graph and Rendering



  • @Tom_H I tried it with a timer but it also does not work.

    Timer {
       id: iTim
       interval: 0
       running: false
       repeat: false
       triggeredOnStart: true
       onTriggered: {
            console.log("onTriggered");
            iBut1.mTxt = "wait"
        }
    }
    

    Without triggeredOnStart: true the triggerSignal is fired after the heavyFunct() is finished.



  • @Tom_H How can I found out that I'm using a non-threaded render loop? In the QQuickFrambufferObject I'm using of course the QQuickFramebufferObject::Renderer.

    "Communication between the item and the renderer should primarily happen via the QQuickFramebufferObject::Renderer::synchronize() function. This function will be called on the render thread while the GUI thread is blocked."

    It's still not clear how the gui and scene graph render works together. Based on the Qt arcticles it seems so that the scene graph render blocks the gui during rendering.

    Is the gui blocked during upload of big Vertex/Index buffer objects?



  • For who is interessted, I handle the problem by using the pressed() signal.

    MouseArea  {
        property bool mRed: false
    
        onClicked: {
           heavyFunct();
           mRed = false;
        }
        onPressed: {
           mRed = true;
        }
        onReleased: {
           mRed = false;
        }
    }
    

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.