3

I'm having an issue with a Qt GUI progress bar. The problem is that for larger files, 350MB and above... the progress bar works as expected towards the start and then it seemingly does not move for some time, then suddenly it jumps to 100% when the job is done. I'm not sure why this is happening, I was wondering if there was some Qt mystery causing this or whether I am doing something wrong.

#include "aClass.h"
#include <QString>
#include <QTextStream>
#include <QByteArray>
#include <QFile>

const char aClass::BLOCK_MODE_CBC = 1;

aClass::aClass()
{
}

qint64 aClass::doWorkA (const QString fileNameSrc, const QString fileNameDst, byte * a, byte * b, aBitSizeInBytes sizeaBytes, RWBufferSizeInBytes rwBufferSize)
{
    QFile infile(fileNameSrc);
    QFile outfile(fileNameDst);

    if(!infile.open(QIODevice::ReadOnly))
        return -1;
    if(!outfile.open(QIODevice::WriteOnly))
        return -1;

    qint64 sizeOfOriginalFileInBytes = infile.size();

    //Set range for progress bar
    int progressMax = sizeOfOriginalFileInBytes / rwBufferSize;
    if(progressMax == 0)
        progressMax = 1;
    emit setRange(0, progressMax);

    byte* readDataBuffer = new byte[rwBufferSize];
    byte* writeDataBuffer = new byte[rwBufferSize];
    qint64 readSize = 0;
    qint64 writeSize = 0;

    int progressCounter = 0;
    while (!infile.atEnd()) {
        readSize = infile.read((char*)readDataBuffer, rwBufferSize);
        writeSize = readSize;

        something.changeData(writeDataBuffer, readDataBuffer, writeSize);

        outfile.write((char*)writeDataBuffer, writeSize); 

        //Update progress bar value
        emit setValue(++progressCounter);
    }
    delete[] readDataBuffer;
    delete[] writeDataBuffer;
    infile.close();
    outfile.close();

    return 0;
}
Chris
  • 17,119
  • 5
  • 57
  • 60
L123
  • 139
  • 4
  • 14
  • 1
    Does calling `qApp->processEvents(QEventLoop::ExcludeUserInputEvents)` after emitting the signal help at all? – Dave Mateer Dec 09 '11 at 18:14
  • Yes, but I'm not sure why this worked since there is only one GUI dialog window with a few simple widgets and no user input while the application was processing. Yet the application was overwhelmed by user input even with no user input and a simple GUI? – L123 Dec 09 '11 at 19:09
  • 1
    The key issue is that Qt does not implement a separate GUI thread from your main thread of execution. So while your main thread is busy, nothing can be updated by Qt. You need to do your work in a separate thread to avoid this problem entirely. – Will Bickford Dec 10 '11 at 02:21

1 Answers1

2

You are blocking the event loop

This is a classic problem of event-based programming. You need to make sure that you never block the event loop in order to keep the GUI responsive. If you don't return control of the main thread to Qt, then it can't update your display.

Qt is designed around the idea that the main GUI thread will never remain busy for very long. It is your job to make sure that long-running tasks do not block the event queue.

Solution 1: Return Control Periodically

This is the processEvents suggestion by user763305 above. Technically this is a stop-gap solution as it just side-steps the problem.

Solution 2: Execute the Work in a Separate Thread

This is the cleaner solution - by splitting your work into a worker thread you allow the GUI to remain responsive to incoming events. Qt provides multiple ways to execute code concurrently. See the links below for more information.

Sources:

Community
  • 1
  • 1
Will Bickford
  • 5,381
  • 2
  • 30
  • 45