简体   繁体   English

Qt5.15:如何从 QtConcurrent function 访问小部件 object

[英]Qt5.15: how to access widget object from a QtConcurrent function

I wish to update a progress bar widget from a QtConcurrent function and stuck on the following problem:我希望从 QtConcurrent function 更新进度条小部件并遇到以下问题:

a) If I declare this function as: a) 如果我将此 function 声明为:

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' ").但是我无法从 function 内部访问我的 GUI 的任何 Qt 小部件(“无法解析标识符'小部件'”)。

b) If I declare this function as: b) 如果我将此 function 声明为:

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.在 Qt 中,所有小部件都应位于主 GUI 线程中。 All other threads shouldn't directly access widgets from the main thread, Qt doesn't guarantee thread safety here.所有其他线程不应该直接从主线程访问小部件,Qt 在这里不保证线程安全。 What is the solution?解决办法是什么? To use Qt's builtin queued mechanisms.使用 Qt 的内置队列机制。 There are two methods.有两种方法。

  1. If there is a QObject derived class in your second thread, you can use a Qt::QueuedConnection Qt::signal/slot connection.如果在第二个线程中有一个 QObject 派生的 class,则可以使用 Qt::QueuedConnection Qt::signal/slot 连接。 You can also use Qt::AutoConnection, which is default, but I prefer to explicitly state what I need.您也可以使用 Qt::AutoConnection,这是默认设置,但我更喜欢明确 state 我需要什么。

From documentation:从文档:

(Qt::AutoConnection) If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. (Qt::AutoConnection) 如果接收器位于发出信号的线程中,则使用 Qt::DirectConnection。 Otherwise, Qt::QueuedConnection is used.否则,使用 Qt::QueuedConnection。 The connection type is determined when the signal is emitted.连接类型在信号发出时确定。

  1. If you do not have any QObjects in your second thread - use QMetaObject::invokeMethod.如果您的第二个线程中没有任何 QObject - 使用 QMetaObject::invokeMethod。

How to provide the caller with the pointer to callee?如何为调用者提供指向被调用者的指针? I would recommend using a closure (a lambda with capture).我建议使用闭包(带捕获的 lambda)。

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.您现在有责任检查捕获的指向小部件的指针指向的有效小部件是否比非 GUI 线程的生命周期长。

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:在 you.cpp 文件的某处:

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");

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM