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

QProgressDialog looks messed up / corrupted when it's first shown



  • I'm trying to write a test before adding a progress bar to my application:

    QProgressDialog progressDialog;
    progressDialog.setWindowTitle("Test");
    progressDialog.setRange(0, 4);
    progressDialog.setLabelText("Updating...");
    progressDialog.show();
    for (i = 0; i < 4; i++)
    {
        progressDialog.setValue(i);
        QApplication::processEvents();
        QThread::sleep(1);
    }
    progressDialog.close();
    

    But when the progress dialogue first appears it is messed up / corrupted:

    0_1527178257575_ProgressDialog.jpg


  • Lifetime Qt Champion

    Hi,

    What version of Qt are you using ?
    On what platform ?
    If Linux:
    What distribution ?
    What desktop environment ?



  • I think its the way your test is structure. The progress dialog does not get to paint itself properly until the event loop gets to run. So until you call processEvents() the dialog will not appear correct.



  • I'm using Qt 5 on Linux Mint 18.1 (Cinnamon).

    I tried adding more "QApplication::processEvents()", but it didn't make any difference.

    I think I will have to create a separate thread for the progress dialogue.


  • Lifetime Qt Champion

    Qt 5 is a bit vague since it goes from 5.0.0 to 5.11.0.

    Did you install it yourself ?
    If not, do you have the same problem with the Qt version provided by Mint ?
    What window manager are you using ?



  • @SGaist
    $ qmake -v
    QMake version 3.0
    Using Qt version 5.6.2 in /home/daniel/anaconda3/lib
    $ wmctrl -m
    Name: Mutter (Muffin)

    But Qt Creator says version 5.5.


  • Lifetime Qt Champion

    How did you determine the version from Qt Creator ?

    In any case, you should first try to build your application with your distribution provided Qt.



  • @SGaist
    I looked at the help about dialogue in Qt Creator to get "5.5".

    Yeah. I'm using the version installed with the Mint software manager (5.5), so it's the same version as I'd get with "apt-get install". I don't know how to access Qt via Anaconda as it is not on the Anaconda menu.



  • I'm still convinced this is a coding issue, not configuration.
    try this to see if the progress dialog is shown correctly: (m_timer is a QTimer)

    void Dialog::on_showProgress1_clicked()
    {
        QProgressDialog *dlg = new QProgressDialog(this);
        connect(dlg, &QProgressDialog::finished, dlg, &QProgressDialog::deleteLater);
        connect(dlg, &QProgressDialog::canceled, this, [=](){
            m_progressVal = 99;  // kind of cheesy, let the timer continue and cleanup
        });
    
        dlg->setRange(0,100);
        dlg->setWindowTitle("Test");
        dlg->setLabelText("Updating...");
        m_progressVal = 0;
    
        auto conn = std::make_shared<QMetaObject::Connection>();
        *conn = connect(&m_timer, &QTimer::timeout, this, [=]() {
            m_progressVal++;
            dlg->setValue(m_progressVal);
    
            if (m_progressVal == dlg->maximum()) {
                m_timer.stop();
                disconnect(*conn);
            }
        });
    
        dlg->show();
    
        m_timer.setInterval(100);
        m_timer.start();
    }
    
    


  • @mranger90

    I got your example to run... nice! How would I adapt it so that I can update the progress bar from within an algorithm (assuming that is possible):

    void myAlgorithm(int n)
    {
        int i;
        for (i = 0; i < n; i++)
        {
            someProcessingFunction(i);
            // update the progress bar here!
        }
    }
    


  • @Guerrian Hi,friend.

    Very good! Don't forget to Mark as Solved in Topic Tools.



  • If you don't pause before the first (not zero) point and process events then the progress dialogue is drawn correctly. Seems like a bug with QProgressDialog.


  • Lifetime Qt Champion

    @Guerrian
    Hi
    QProgressDialog is older than god so its very unlikely you found a bug in 2018 :)
    also when you use stuff like
    QApplication::processEvents();
    QThread::sleep(1);
    it means you try to loop in a GUI application and it always do odd stuff as you are stangulating the event loop. QApplication::processEvents() can sometimes help
    but its not a cure all loops magic call.

    signals and slot often a way better choice as it plays nice with the event loop.



  • @mrjj
    Can I do this with two threads, one for the GUI and the other for the algorithm?


  • Lifetime Qt Champion

    @Guerrian
    Hi, yes if algorithm is heavy then its be best solution.
    You already have the GUI thread.
    So if you move the algorithm class to a thread and
    emit a signal to tell the progressbar to update then it should work lovely.
    https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
    so myAlgorithm would be the task object and moved to thread.



  • I followed this path and it is almost working. Unfortunately the cancel button on the progress bar is disabled. It remains disabled even after successfully updating the progress bar. The only thread I could find on this problem is here:
    https://forum.qt.io/topic/26619/cancel-button-on-qprogressdialog-is-unresponsive-solved
    Like the author says though you don't need to connect the cancel button to a slot.

    I am setting up the dialog like this now:

    dialog = new QProgressDialog(tr("Performing task") + "...", tr("Cancel"), 0, 4, this);
    dialog->setLabelText("Updating...");
    dialog->setWindowModality(Qt::WindowModal);
    connect(task, SIGNAL(advance()), this, SLOT(advance()));
    connect(dialog, &QProgressDialog::finished, dialog, &QProgressDialog::deleteLater);
    connect(dialog, &QProgressDialog::canceled, this, [=] ()
    {
        thread->quit();
        thread->wait();
        dialog->close();
    });
    

    I'm showing the dialog like this:

        dialog->setValue(0);
        dialog->show();
    

    I'm advancing the progress bar like this:

    void MainWindow::advance()
    {
        dialog->setValue(dialog->value() + 1);
        QApplication::processEvents();
    }
    

    Another strange problem which I am encountering is that the progress bar / task is sometimes started even when I click on the menu but not the menu item. I am connecting the menu item to the function using:

    connect(ui->actionTask, &QAction::triggered, this, &MainWindow::runTask);
    

  • Lifetime Qt Champion

    Hi
    Does it enter the "cancel" lambda ?



  • @mrjj
    No, it can't, because the cancel button is disabled on the QProgressDialog.


  • Lifetime Qt Champion

    But do you mean is disabled as in setEnabled(false)
    or simply is unresponsive ?



  • @mrjj
    I think the problem is that I disabled the menu using:

    setEnabled(false);
    

    When I click cancel the lambda is called twice.

    However I don't understand why the action is triggered even when I just select the menu and not the menu item. Perhaps this merits another question on this forum.

    Is it neccessary to use a mutex and flag that the algorithm has been cancelled?


Log in to reply