有没有办法从 QML WorkerScript 运行 C++?

2022-01-19 00:00:00 multithreading qt qml c++

我有一个缓慢的 I/O 操作,需要通过 QML UI 进行控制.I/O 接口是 C++ 语言.基本上,当用户按下按钮时,我需要发送消息并从设备获得响应.我希望用户在等待响应时能够做其他事情.WorkerScript 似乎是实现这一点的最简单方法,但是由于正常的 QDeclarativeContext 没有传递到线程中,我如何将我的 C++ 接口放入脚本中?有没有办法将 C++ 导入 QML 的 javascript?我什至不需要在主线程中维护 C++ 上下文,我完全可以将它完全存在于工作线程中并且只是来回传递消息.

澄清:@dtech 的回答满足了我目前的需求,但我仍然想知道这个问题的答案:是否有可能将 C++(即使不是有状态的)放入 WorkerScript.

I have a slow I/O operation that I need to control from a QML UI. The I/O interface is in C++. Basically, when a user presses a button, I need to send a message and get a response from the device. I want the user to be able to do other things while waiting for a response. WorkerScript seems like the easiest way to make this happen, but how do I get my C++ interface into the script since the normal QDeclarativeContext doesn't pass into the thread? Is there a way to import C++ into QML's javascript? I don't even need to maintain the C++ context in the main thread, I'd be fine with it living entirely in the worker and just passing messages back and forth.

Clarifications: @dtech's answer satisfies my current need, but I would still like to know the answer to the question: is it possible to get C++ (even if not stateful) into a WorkerScript.

推荐答案

当您可以选择将 QObject 放入专用线程中,执行代码而不阻塞主线程时,为什么要这样做,并以异步方式与 QML 来回交流和交付结果?

Why would you do that when you have the option to put QObjects into dedicated threads, execute code without blocking the main thread, and communicate and deliver results back and forth to QML asyncronously?

您不需要 WorkerScript,这也不是它的预期用途.而且由于您的代码无论如何都是 C++,您所需要的只是 QThreadQObject.

You don't need WorkerScript, nor is this its intended use. And since your code is C++ anyway, all you need is QThread and QObject.

这是一个简单的例子:

class Worker : public QObject {
    Q_OBJECT
  public slots:
    void doWork() {
      int i = 0;
      while (i < 100) {
        result(i++);
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
      }
    }
  signals:
    void result(int r);
};

class Controller : public QObject {
    Q_OBJECT
  public:
    Controller() {
      w = new Worker;
      t = new QThread;
      w->moveToThread(t);
      connect(this, SIGNAL(start()), w, SLOT(doWork()));
      connect(w, SIGNAL(result(int)), this, SIGNAL(result(int)));
      t->start();
    }
  private:
    Worker * w;
    QThread * t;
  signals:
    void start();
    void result(int r);
};

// in main.cpp
  Controller cw;
  engine.rootContext()->setContextProperty("Work", &cw);
  engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); // load main qml


// QML

  Column {
    Button {
      id: start
      onClicked: Work.start()
    }
    Text {
      id: res
    }
  }

  Connections {
    target: Work
    onResult: res.text = r
  }

它是一个简单的阻塞工作者,它将阻塞其线程大约 50 秒,但仍然能够发出将在 QML 端更新的结果,同时保持 GUI 线程空闲.请注意,一旦调用了工作函数,就不能以任何方式中断、暂停或控制它,如果需要,您将必须实现 非阻塞工作者.也不需要 C++ 控制器作为 QML 和线程对象"之间的中介,因为 QML 似乎不能直接与这些对象相处.

It is a simple blocking worker that will block its thread for about 50 seconds, but nonetheless will be able to emit results that will be updated on the QML side, while keeping the GUI thread free. Note that once the work function is invoked, it is not possible to interrupt, pause, or control it in any way, if that is required, you will have to implement a non-blocking worker instead. Also not the need of a C++ controller to be present to act as a mediator between QML and the "threaded object", as it seems that QML doesn't get along with such objects directly.

相关文章