Reputation: 2394
I am connecting a ProgressBar
to two Buttons
. The ProgressBar
will do a computation of a loop as soon as I push the button. The computation will be erased if I will push the other button. I still haven't implemented the pause
button.
The print screen of what I am trying to achieve is below and in case needed the whole code of the minimal verifiable example is available here:
The problem is that as soon as I connect the ProgressBar
with my main.cpp
file I have a bunch of errors all that look like the following:
class ProgressDialog has no member named...
code is below:
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickView>
#include "progressbardialog.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQuickView view;
ProgressBarDialog progressDialog;
// One way but it does not work
// engine.rootContext()->setContextProperty("control", QVariant::fromValue(progressDialog.refModel()));
// Another way but this also does not work
view.setSource(QUrl::fromLocalFile("main.qml"));
QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
return app.exec();
}
progressbardialog.h
#ifndef PROGRESSBARDIALOG_H
#define PROGRESSBARDIALOG_H
#include <QObject>
#include <QFutureWatcher>
class ProgressBarDialog : public QObject
{
Q_OBJECT
Q_PROPERTY(float progress READ progress WRITE setProgress NOTIFY progressChanged)
public:
ProgressBarDialog();
float progress(int &iterator);
// I will use this as a reference to pass to main.cpp using setContextProperty()
QObject &refModel()
{
return m_Model;
}
public Q_SLOTS:
void startComputation();
void cancelComputation();
signals:
void progressChanged();
private:
int m_progressValue;
QObject m_Model;
QFutureWatcher<void> m_futureWatcher;
};
#endif // PROGRESSBARDIALOG_H
progressbardialog.cpp
#include "progressbardialog.h"
#include <QtConcurrent/QtConcurrentMap>
ProgressBarDialog::ProgressBarDialog()
{}
void spin(int &iteration)
{
const int work = 1000 * 1000 * 40;
volatile int v = 0;
for(int j = 0; j < work; ++j)
++v;
}
float ProgressBarDialog::progress(int &iterator)
{
(void) iterator;
const int work = 1000 * 1000 * 40;
volatile int v = 0;
for(int j = 0; j < work; ++j)
++v;
emit progressChanged();
}
void ProgressBarDialog::startComputation()
{
// Prepare the vector
QVector<int> vector;
for(int i = 0; i < 40; ++i)
vector.append(i);
const QFuture<void> future = QtConcurrent::map(vector, spin);
m_futureWatcher.setFuture(future);
}
void ProgressBarDialog::cancelComputation()
{
m_futureWatcher.cancel();
}
and finally the main.qml
import QtQuick 2.12 // for the Item
import QtQuick.Controls 2.12 // for ApplicationWindow
import QtQuick.Layouts 1.12
ApplicationWindow {
visible: true
width: 440
height: 480
title: qsTr("Progress Bar")
ColumnLayout {
spacing: 10
width: parent.width
GroupBox {
id: box1
title: "Start - Stop"
font.pointSize: 20
Layout.alignment: parent.width
spacing: 10
GridLayout {
width: parent.width
columns: 1
RowLayout {
spacing: 200
Layout.fillWidth: true
Layout.fillHeight: false
Button {
id: buttonStart
text: "Start"
font.pointSize: 15
enabled: !progressDialog.active
onClicked: progressDialog.startComputation()
}
Button {
id: buttonFinish
text: "Finish"
font.pointSize: 15
enabled: progressDialog.cancelComputation()
}
}
}
}
GroupBox {
id: boxprogress
title: "Progressbar"
font.pointSize: 20
Layout.alignment: parent.width
spacing: 10
GridLayout {
width: parent.width
columns: 1
RowLayout {
Layout.fillWidth: true
Layout.fillHeight: false
ProgressBar {
id: progressbar_id
Layout.fillWidth: true
Layout.fillHeight: true
width: parent.width
// These are hard-coded values to confirm it is working
from: 0
to: 100
value: 5
onValueChanged: {
console.log("Progressbar value changed: ", progressbar_id.value)
}
onVisibleChanged: {
console.log("Progressbar visibility changed: ", progressbar_id.visible)
}
}
Connections {
target: progressDialog
onProgressChanged: progressbar_id.value = progress;
}
// This is working if clicking on the progressbar
MouseArea {
anchors.fill: parent
onClicked: progressbar_id.value += 5;
}
}
}
}
}
}
What I tried so far :
1) In order to prove myself that the ProgressBarDialog
is correctly working I tried it before as a stand alone main.qml
using hard-coded values (which I left in the code so you can see what I have done). But as soon as I started implementing it in the .cpp
file and setting the Q_PROPERTY
I received all the errors I posted on the second screenshot.
2) I am sure about the procedure taken so far because: a) According to the official documentation and from this post because I will need to check the process of a long running operations; b) According to QtConcurrent the process has a better possibility to be checked, and that is exactly what I did using QtConcurrent::map()
3) I am using the following statement in the progressbardialog.h to make sure that the object is correctly connected and listens to the QML
file:
QObject &refModel()
{
return m_Model;
}
But this did n't show and substancial improvements. Therefore digging more into the process I was thinking that it should have been the case to use setContextProperty()
, whih cled me to the next point.
4) According to the official documentation and according to this post here I thought I would have fix the error, but it still remains.
I am runnign out of ideas and anyone who may have had this problem, please point to the right direction for a possible solution.
Upvotes: 1
Views: 1412
Reputation: 192
Q_PROPERTY is designed to easier read/write/react to variable change (C++ side) on the QML side. To complete your example with variable read/write/notify add correct getter/setter (signal is already ok).
float progress();
void setProgress(float);
If you want to call a function from QML mark it Q_INVOKABLE instead. Also what is the point of volatile in your code?
So to sum up, mark your iteration function as a Q_INVOKABLE. It will increment some internal progress value and then emit progressChanged(). This should cause QML side to update.
Upvotes: 2