Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Qt] QProgressDialog ralentit une opération

Sujet résolu
    15 janvier 2019 à 17:18:01

    Bonjour,

    Je viens vers vous car j'ai un souci assez contraignant avec QProgressDialog.

    J'ai une fonction qui se charge de créer une scène composée d'une matrice de rectangle et parfois l'opération peut prendre quelques secondes selon la taille de la matrice. Du coup je me suis dit que j'allais ajouter une barre de progression pendant l'opération sauf que celle-ci est considérabelement ralentie avec l'ajout d'un QProgressDialog.

    Pour donner une idée, j'ai fait quelques test pour mesurer le temps d'exécution pour la création de la scene avec et sans progression :

    Sans QProgressDialog :

    120*120 = 123ms (0.12 sec)
    150*150 = 271ms (0.27 sec)

    Avec QProgressDialog :

    120*120 = 8264ms (8 sec)
    150*150 = 31268ms (31 sec)

    Et voici la fonction :

    void MapScene::createMatrix(int tileWidth, int tileHeight, int rows, int cols)
    {
        clear();
        m_tiles.clear();
        m_tilesTextures.clear();
        m_tilesTexturesNames.clear();
    
        m_tileSize = QSize{tileWidth, tileHeight};
        m_rows = rows;
        m_cols = cols;
    
        QProgressDialog progress{"Creating tiles...", "Cancel", 0, rows*cols};
        progress.setWindowModality(Qt::WindowModal);
        progress.setMinimumDuration(0);
        progress.show();
    
        /*QElapsedTimer chrono{};
        chrono.start();*/
    
        for(int i = 0; i < rows; ++i){
            for(int j = 0; j < cols; ++j){
                m_tiles.push_back(addRect(j*tileWidth, i*tileHeight, tileWidth, tileHeight));
                m_tilesTextures.push_back(addPixmap(QPixmap{}));
                m_tilesTextures.back()->setPos(j*tileWidth, i*tileHeight);
                m_tilesTexturesNames.push_back("");
                progress.setValue(i*cols+j);
                if(progress.wasCanceled()){
                    clear();
                    m_tiles.clear();
                    m_tilesTextures.clear();
                    m_tilesTexturesNames.clear();
                    break;
                }
            }
        }
    
        //qDebug() << chrono.elapsed();
    
        progress.setValue(rows*cols);
    }

    Une idée de pourquoi QProgressDialog ralentit l'opération à ce point ?

    Merci :)

    ---------------------------------------------------

    EDIT : Ok j'ai repéré d'où venait l'embrouille. En fait en interne, QProgressDialog::setValue() appelle QApplication::processEvents() (et quand c'est des milliers fois autant dire que les performance en prennent un coup :)).

    Du coup pour pallier à ça j'ai limité la manoeuvre avec 2-3 conditions :

    void MapScene::createMatrix(int tileWidth, int tileHeight, int rows, int cols)
    {
        clearAllContainers();
    
        m_tileSize = QSize{tileWidth, tileHeight};
        m_rows = rows;
        m_cols = cols;
    
        QProgressDialog progress{"Creating tiles...", "Cancel", 0, 100};
        progress.setWindowModality(Qt::WindowModal);
        progress.setMinimumDuration(0);
        progress.setValue(0);
        progress.show();
    
        int steps{0};
        const int totalTiles = rows*cols;
        
        for(int i = 0; i < rows; ++i){
            for(int j = 0; j < cols; ++j){
    
                m_tiles.push_back(addRect(j*tileWidth, i*tileHeight, tileWidth, tileHeight));
                m_tilesTextures.push_back(addPixmap(QPixmap{}));
                m_tilesTextures.back()->setPos(j*tileWidth, i*tileHeight);
                m_tilesTexturesNames.push_back("");
    
                if(progress.wasCanceled()){
                    clearAllContainers();
                    break;
                }
    
                // If 1% of totalTiles >= 1 tile
                if(totalTiles/100.f >= 1){
                    // Check if current index >= 1% of total * current step
                    if((i*cols+j) >= (totalTiles/100.f)*steps){
                        // 1 step = 1%
                        ++steps;
                        progress.setValue(steps);
                    }
                } else {
                    // Display % relative to current tile
                    progress.setValue(static_cast<int>((i*cols+j)/(totalTiles/100.f)));
                }
            }
        }
    
        progress.setValue(100);
    }

    Maintenant c'est 0.5sec pour créer une matrice de 150*150. Rien à voir avec les 31sec du début :D.

    -
    Edité par Guit0Xx 15 janvier 2019 à 20:33:00

    • Partager sur Facebook
    • Partager sur Twitter

    ...

    [Qt] QProgressDialog ralentit une opération

    × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
    × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
    • Editeur
    • Markdown