Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

How to make one second delay in loop execution



  • void GraphAlgorithm::BFS(int startVertex)
    {
        visited = new bool[vertexNum];
        for(int i=0; i<vertexNum; i++)
            visited[i] = false;
    
        QLinkedList<int> queue;
    
        visited[startVertex] = true;
        queue.push_back(startVertex);
    
        QLinkedList<int>::iterator i;
    
        while(!queue.empty())
        {
            int currVertex = queue.front();
            queue.pop_front();
    
    
            for(i=adjList[currVertex].begin(); i!= adjList[currVertex].end(); ++i)
            {
                int adjVertex = *i;
                if(!visited[adjVertex])
                {
                    visited[adjVertex] = true;
                    queue.push_back(adjVertex);
    
                    scene->removeItem(node[*i]);
                    node[*i] = new Node(srcNode, 1);
                    node[*i]->setPos(nodePos[*i][0], nodePos[*i][1]);
                    scene->addItem(node[*i]);
                    
                }
            }
        }
    }
    

    Hello. I have a problem for making delay in loop execution.
    I want to make one second delay in loop execution.
    scene->addItem(node[*i]) this will show me change at graphicsview.

    I tried QTread::sleep(1); after scene->addItem, but it don't work like my idea.

    Thank you.


  • Lifetime Qt Champion

    Since sleep() blocks the eventloop it will not help.You maybe can fire a QTimer to add the stuff later on.



  • Like Christian already mentioned you have to continue processing the main loop. Basically, this means using a QTimer. This also means that you have to break up your loops and make slots from the loop bodies. A little less work is to use lambdas instead. Here's my try at transforming your code (didn't try to compile it):

    void GraphAlgorithm::BFS(int startVertex)
    {
        visited = new bool[vertexNum];
        for(int i=0; i<vertexNum; i++)
            visited[i] = false;
    
        QLinkedList<int> queue;
    
        visited[startVertex] = true;
        queue.push_back(startVertex);
    
        QObject *dummy = new QObject(); // we need an object as receiver for signals
    
        // body of inner loop -> calls next iteration at end
        auto innerLoop = [&](QLinkedList<int>::iterator &i)
        {
            int adjVertex = *i;
            if(!visited[adjVertex])
            {
                visited[adjVertex] = true;
                queue.push_back(adjVertex);
        
                scene->removeItem(node[*i]);
                node[*i] = new Node(srcNode, 1);
                node[*i]->setPos(nodePos[*i][0], nodePos[*i][1]);
                scene->addItem(node[*i]);
            }
    
            // call next iteration
            if(i!= adjList[currVertex].end())
            {
                ++i;
                QTimer::singleShot(1000, dummy, [&](){ innerLoop(i); }); // put next iteration in event loop
            }
        }
    
        // body of outer loop
        auto outerLoop = [&](int currVertex)
        {
            QLinkedList<int>::iterator i = adjList[currVertex].begin();
    
            innerLoop(i); // call first iteration directly
    
            // call next iteration
            if(!queue.empty())
            {
                int currVertex = queue.front();
                queue.pop_front();
    
                // maybe you don't want this asynchronously
                QTimer::singleShot(1000, dummy, [&](){ outerLoop(currVertex); });
            }
            else
            {
                dummy->deleteLater();  // clean up after ourselves...
            }
        }
    
        if(!queue.empty())
        {
            int currVertex = queue.front();
            queue.pop_front();
       
            outerLoop(currVertex); // start outer loop
        }
        else
        {
            delete dummy;
        }
    }
    

    I am not entirely sure if you can call lambdas recursively. My guess, though, is you can't. This would mean that you need to put the lambdas into separate slots. In that case you cannot capture local variables, but instead you would have to provide them as parameters as well.



  • @SimonSchroeder
    I haven't read your code through, but there is no reason one cannot call lambdas recursively in principle; the problem is getting a reference to an anonymous lambda in order to call it.

    https://riptutorial.com/cplusplus/example/8508/recursive-lambdas discusses some approaches. std::function seems to be a favourite. https://stackoverflow.com/questions/2067988/recursive-lambda-functions-in-c11 & https://stackoverflow.com/questions/45091152/return-recursive-lambda-from-function-in-c discuss this and alternatives.



  • I you just want the items to appear you don't need to add a delay, just add QApplication::processEvents(); inside the loop


Log in to reply