Emanuele
Emanuele

Reputation: 2394

Qt5: How to properly set a ProgressBar using State

I have a small example of a ProgressBar that when it finishes to execute the loop should notify the user that the calculation finished. To be specific, after the ProgressBar finishes, a Text should turn from Connecting... to Connected.

The problem is that as soon as the ProgressBar arrives at the end of the calculation the text does not change. I think that the problem might be on how I set the finished function of the ProgressBar. I have been trying to solve this problem for the last hours but there is some error I can't catch.

Below the most important part of the code:

progressbardialog.h

class ProgressBar : public QObject
{
    Q_OBJECT
    Q_PROPERTY(float progress READ progress NOTIFY progressChanged)
    Q_PROPERTY(bool running READ running NOTIFY runningChanged)
    Q_PROPERTY(bool finished READ finished NOTIFY finishedChanged)
public:
    ProgressBar();
    float progress();
    bool running();
    bool finished();

public Q_SLOTS:
    void startComputation();
    void cancelComputation();
    void finishComputation();
private Q_SLOTS:
    void updateProgress(int value);
signals:
    void progressChanged();
    void runningChanged();
    void finishedChanged();
private:
    bool m_running = false;
    int m_progressValue = 0;
    int m_finished = true;
    QVector<int> vector;
    QObject m_Model;
    QFutureWatcher<void> m_futureWatcher;
};

progressbardialog.cpp

ProgressBar::ProgressBar()
{}

void spinEC(int &iteration)
{
    Q_UNUSED(iteration)
    const int work = 1000 * 1000 * 400;
    volatile int v = 0;
    for(int j = 0; j < work; ++j)
        ++v;
}

float ProgressBar::progress()
{
    return m_progressValue;
}

bool ProgressBar::running()
{
    return m_running;
}

bool ProgressBar::finished()
{
    return m_finished;
}

void ProgressBar::startComputation()
{
    m_running = true;
    emit runningChanged();
    // Prepare the vector
    vector.clear();
    for(int i = 0; i < 40; ++i)
        vector.append(i);
    const QFuture<void> future = QtConcurrent::map(vector, spinEC);
    m_futureWatcher.setFuture(future);
    connect(&m_futureWatcher, &QFutureWatcher<void>::progressValueChanged,
            this, &ProgressBar::updateProgress);
}

void ProgressBar::cancelComputation()
{
    m_running = false;
    emit runningChanged();
}

void ProgressBar::finishComputation()
{
    m_progressValue = false;
    emit progressChanged();
}

void ProgressBar::updateProgress(int value)
{
    m_progressValue = value;
    emit progressChanged();
}

main.qml

Text {
    id: connected
    text: qsTr("Not-Connected")
    color: "red"
    font.pointSize: 15
    horizontalAlignment: Text.AlignRight
    Layout.fillWidth: true

    states: [
        State {
            name: "connecting"
            when: pBar.running
            PropertyChanges {
                target: connected
                text: qsTr("Connecting...")
                color: "blue"
                font.bold: true
            }
        },
        State {
            name: "connected"
            when: pBar.finished
            PropertyChanges {
                target: connected
                text: qsTr("Yes! Connected...")
                color: "green"
                font.bold: true
            }
        }
    ]
}

EDITS:

On the progressbar.cpp I also tried the following in the function void ProgressBar::finishComputation() but also it didn't work:

void ProgressBar::finishComputation()
{
    m_progressValue = false;
    emit finishedChanged();
}

What I have done so far is debugging the code as much as possible and after debugging line per line (I could not find out and decided to go line by line) I figured out that the problem is on the Q_PROPERTY related to the finished function I wrote. All the other functions such as running and progress are working perfectly and applied the same exact philosophy to the finished function to notify the end of the calculation and, therefore, change the State from A to B of the Text.

What am I missing out in the Progressbar that is keeping me from finishing the exercise? Thanks for shedding light on this matter.

Upvotes: 0

Views: 309

Answers (1)

luffy
luffy

Reputation: 2388

The problem could be that m_finished is initialized with true in your header:

int m_finished = true;

So when the signal is emitted after the computation is done, QML doesn't detect any changes because the variable is still true!

Try changing it to false before starting the computation. Also don't forget to emit the changed signal each time running or finished change value:

void ProgressBar::startComputation()
{
    m_running = true;
    emit runningChanged();

    m_finished = false;
    emit finishedChanged();

    ...
}

void ProgressBar::finishComputation()
{
    m_finished = true;
    emit finishedChanged();

    m_running = false;
    emit runningChanged();
}

EDIT:

The Problem is that finishComputation is never called! A possible solution would be to add a check in your updateProgress function:

void ProgressBar::updateProgress(int value)
{
    m_progressValue = value;
    emit progressChanged();

    if (m_progressValue == 40)
        finishComputation();
}

enter image description here

Upvotes: 2

Related Questions