I wish to update a progress bar widget from a QtConcurrent function and stuck on the following problem:
a) If I declare this function as:
void myRunFunction(QString str)
then I successfully program it as concurrent by:
QFuture<void> t1 = QtConcurrent::run(myRunFunction, QString("A"));
BUT I cannot access to any Qt widget of my GUI from inside the function ("unable to resolve identifier 'widget' ").
b) If I declare this function as:
void mainForm::myRunFunction(QString str)
then I successfully access my widgets inside it BUT cannot longer program it as concurrent getting the compiler error:
error: invalid use of non-static member function ‘void mainForm::myRunFunction(QString)’
at line:
QFuture<void> t1 = QtConcurrent::run(myRunFunction, QString("A"));
How can I solve the problem? Many thanks in advance, Marco
In Qt all widgets should live in the main GUI thread. All other threads shouldn't directly access widgets from the main thread, Qt doesn't guarantee thread safety here. What is the solution? To use Qt's builtin queued mechanisms. There are two methods.
From documentation:
(Qt::AutoConnection) If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used. The connection type is determined when the signal is emitted.
How to provide the caller with the pointer to callee? I would recommend using a closure (a lambda with capture).
But be careful about lifetimes of your objects. It is your responsibility now to check that captured pointer to the widget points to the valid widget longer than the lifetime of non-GUI thread.
According to your code, the second variant is suited better for you. There is a small example:
// guiwidget.h
class GuiWidget : public QWidget
{
Q_OBJECT
public:
GuiWidget(QWidget *parent = nullptr);
~GuiWidget() {};
// public function for variant 2
void function(int data) {
// update widget
}
// slot for variant 1
public slots:
void function_slot(int data) {
// update widget
}
};
And somewhere in you.cpp file:
GuiWidget *widget = new GuiWidget(this);
// declare a lambda
auto f = [widget] (QString str)
{
for (int i = 0; i < str.toInt(); ++i) {
// do some job
// ...
// job is done
// send progress data to mainwidget
QMetaObject::invokeMethod(widget, [widget, i] ()
{
widget->function(i);
}, Qt::QueuedConnection);
}
};
auto t1 = QtConcurrent::run(f, "100");
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.